composio_sdk/models/
internal.rs1use serde::{Deserialize, Serialize};
7use std::sync::Arc;
8
9use crate::client::ComposioClient;
10use crate::error::ComposioError;
11use crate::models::base::{BaseResource, Resource, TelemetryContext};
12
13const INTERNAL_SDK_REALTIME_CREDENTIALS_ENDPOINT: &str = "/api/v3/internal/sdk/realtime/credentials";
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct SDKRealtimeCredentialsResponse {
19 pub pusher_key: String,
21 pub project_id: String,
23 pub pusher_cluster: String,
25}
26
27#[derive(Clone)]
32pub struct Internal {
33 base: BaseResource,
34}
35
36impl Internal {
37 pub fn new(client: Arc<ComposioClient>) -> Self {
39 Self {
40 base: BaseResource::new(client),
41 }
42 }
43
44 pub fn with_telemetry_context(
46 client: Arc<ComposioClient>,
47 telemetry_context: TelemetryContext,
48 ) -> Self {
49 Self {
50 base: BaseResource::with_telemetry_context(client, telemetry_context),
51 }
52 }
53
54 pub async fn get_sdk_realtime_credentials(
98 &self,
99 ) -> Result<SDKRealtimeCredentialsResponse, ComposioError> {
100 let start_time = std::time::SystemTime::now();
101 let mut telemetry_data = self.create_method_event(
102 "Internal.get_sdk_realtime_credentials",
103 None,
104 );
105
106 let url = format!(
107 "{}{}",
108 self.client().config().base_url,
109 INTERNAL_SDK_REALTIME_CREDENTIALS_ENDPOINT
110 );
111
112 let result = crate::retry::with_retry(&self.client().config().retry_policy, || async {
114 let response = self
115 .client()
116 .http_client()
117 .get(&url)
118 .header("x-api-key", &self.client().config().api_key)
119 .send()
120 .await
121 .map_err(ComposioError::NetworkError)?;
122
123 if !response.status().is_success() {
125 return Err(ComposioError::from_response(response).await);
126 }
127
128 let credentials: SDKRealtimeCredentialsResponse = response
130 .json()
131 .await
132 .map_err(ComposioError::NetworkError)?;
133
134 Ok(credentials)
135 })
136 .await;
137
138 if let Some(ref mut data) = telemetry_data {
140 let duration_ms = std::time::SystemTime::now()
141 .duration_since(start_time)
142 .unwrap()
143 .as_millis() as f64;
144
145 data.duration_ms = Some(duration_ms);
146
147 let event_type = if let Err(ref e) = result {
148 data.error = Some(crate::models::telemetry::ErrorData {
149 name: "ComposioError".to_string(),
150 code: None,
151 error_id: None,
152 message: Some(e.to_string()),
153 stack: None,
154 });
155 crate::models::telemetry::EventType::Error
156 } else {
157 crate::models::telemetry::EventType::Metric
158 };
159
160 self.push_telemetry_event((event_type, data.clone()));
161 }
162
163 result
164 }
165}
166
167impl Resource for Internal {
168 fn client(&self) -> &ComposioClient {
169 self.base.client()
170 }
171
172 fn telemetry_context(&self) -> &TelemetryContext {
173 self.base.telemetry_context()
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use crate::client::ComposioClient;
181 use wiremock::{
182 matchers::{method, path},
183 Mock, MockServer, ResponseTemplate,
184 };
185
186 #[tokio::test]
187 async fn test_get_sdk_realtime_credentials_success() {
188 let mock_server = MockServer::start().await;
189
190 let response_body = serde_json::json!({
191 "pusher_key": "test_pusher_key_123",
192 "project_id": "proj_test_456",
193 "pusher_cluster": "us2"
194 });
195
196 Mock::given(method("GET"))
197 .and(path("/api/v3/internal/sdk/realtime/credentials"))
198 .respond_with(ResponseTemplate::new(200).set_body_json(&response_body))
199 .mount(&mock_server)
200 .await;
201
202 let client = Arc::new(
203 ComposioClient::builder()
204 .api_key("test_key")
205 .base_url(mock_server.uri())
206 .build()
207 .unwrap(),
208 );
209 let internal = Internal::new(client);
210
211 let result = internal.get_sdk_realtime_credentials().await;
212 assert!(result.is_ok());
213
214 let credentials = result.unwrap();
215 assert_eq!(credentials.pusher_key, "test_pusher_key_123");
216 assert_eq!(credentials.project_id, "proj_test_456");
217 assert_eq!(credentials.pusher_cluster, "us2");
218 }
219
220 #[tokio::test]
221 async fn test_get_sdk_realtime_credentials_unauthorized() {
222 let mock_server = MockServer::start().await;
223
224 Mock::given(method("GET"))
225 .and(path("/api/v3/internal/sdk/realtime/credentials"))
226 .respond_with(
227 ResponseTemplate::new(401).set_body_json(serde_json::json!({
228 "message": "Invalid API key",
229 "code": "UNAUTHORIZED",
230 "status": 401
231 })),
232 )
233 .mount(&mock_server)
234 .await;
235
236 let client = Arc::new(
237 ComposioClient::builder()
238 .api_key("invalid_key")
239 .base_url(mock_server.uri())
240 .build()
241 .unwrap(),
242 );
243 let internal = Internal::new(client);
244
245 let result = internal.get_sdk_realtime_credentials().await;
246 assert!(result.is_err());
247
248 if let Err(ComposioError::ApiError { status, .. }) = result {
249 assert_eq!(status, 401);
250 } else {
251 panic!("Expected ApiError with status 401");
252 }
253 }
254
255 #[tokio::test]
256 async fn test_sdk_realtime_credentials_response_deserialization() {
257 let json = r#"{
258 "pusher_key": "abc123",
259 "project_id": "proj_xyz",
260 "pusher_cluster": "eu"
261 }"#;
262
263 let response: SDKRealtimeCredentialsResponse = serde_json::from_str(json).unwrap();
264 assert_eq!(response.pusher_key, "abc123");
265 assert_eq!(response.project_id, "proj_xyz");
266 assert_eq!(response.pusher_cluster, "eu");
267 }
268}