1use std::sync::Arc;
2
3use reqwest::header::{HeaderValue, AUTHORIZATION};
4
5use crate::auth::Auth;
6use crate::error::ManagerError;
7use crate::gen::auth::apis::configuration::Configuration as AuthConfig;
8use crate::gen::manager::apis::configuration::Configuration as ManagerConfig;
9use crate::gen::task_automation::apis::configuration::Configuration as TaskAutomationConfig;
10use crate::gen::task_schedule::apis::configuration::Configuration as TaskScheduleConfig;
11use crate::gen::user::apis::configuration::Configuration as UserConfig;
12use crate::resources::agents::{AgentGroupsResource, AgentsResource};
13use crate::resources::applications::{ApplicationsResource, LocalAutomationsResource};
14use crate::resources::auth::AuthResource;
15use crate::resources::automations::AutomationsResource;
16use crate::resources::babeldesk::{BabeldeskResource, BabeldeskWidgetsResource};
17use crate::resources::businesshours::BusinessHoursResource;
18use crate::resources::calendars::CalendarsResource;
19use crate::resources::calls::{CallsResource, ReportingResource};
20use crate::resources::campaigns::CampaignsResource;
21use crate::resources::conferences::ConferencesResource;
22use crate::resources::conversations::ConversationsResource;
23use crate::resources::dashboards::DashboardsResource;
24use crate::resources::dialer::{DialerBehavioursResource, DialerResource};
25use crate::resources::events::EventsResource;
26use crate::resources::expressions::ExpressionsResource;
27use crate::resources::files::FilesResource;
28use crate::resources::integrations::IntegrationsResource;
29use crate::resources::logs::LogsResource;
30use crate::resources::me::MeResource;
31use crate::resources::metrics::MetricsResource;
32use crate::resources::numbers::NumbersResource;
33use crate::resources::outbound::OutboundResource;
34use crate::resources::phonebook::PhonebookResource;
35use crate::resources::prompts::PromptsResource;
36use crate::resources::queues::{QueueSelectionsResource, QueuesResource};
37use crate::resources::recordings::RecordingsResource;
38use crate::resources::routing::RoutingResource;
39use crate::resources::schedules::TaskSchedulesResource;
40use crate::resources::sessions::SessionsResource;
41use crate::resources::settings::SettingsResource;
42use crate::resources::sms::SmsResource;
43use crate::resources::system::SystemResource;
44use crate::resources::tasks::{
45 TaskMetricsResource, TaskScriptsResource, TaskSecretsResource, TaskSelectionConfigResource,
46 TasksResource,
47};
48use crate::resources::triggers::TriggersResource;
49use crate::resources::users::UsersResource;
50use crate::retry::RetryPolicy;
51
52pub const DEFAULT_BASE_URL: &str = "https://services.babelforce.com";
54
55pub struct ManagerClient {
58 pub users: UsersResource,
60 pub agents: AgentsResource,
62 pub me: MeResource,
64 pub calls: CallsResource,
66 pub sms: SmsResource,
68 pub numbers: NumbersResource,
70 pub conferences: ConferencesResource,
72 pub queues: QueuesResource,
74 pub recordings: RecordingsResource,
76 pub routing: RoutingResource,
78 pub triggers: TriggersResource,
80 pub automations: AutomationsResource,
82 pub integrations: IntegrationsResource,
84 pub outbound: OutboundResource,
86 pub phonebook: PhonebookResource,
88 pub campaigns: CampaignsResource,
90 pub business_hours: BusinessHoursResource,
92 pub calendars: CalendarsResource,
94 pub conversations: ConversationsResource,
96 pub dashboards: DashboardsResource,
98 pub dialer: DialerResource,
100 pub sessions: SessionsResource,
102 pub prompts: PromptsResource,
104 pub babeldesk: BabeldeskResource,
106 pub events: EventsResource,
108 pub expressions: ExpressionsResource,
110 pub files: FilesResource,
112 pub logs: LogsResource,
114 pub metrics: MetricsResource,
116 pub system: SystemResource,
118 pub settings: SettingsResource,
120 pub applications: ApplicationsResource,
122 pub tasks: TasksResource,
124 pub schedules: TaskSchedulesResource,
126 pub auth: AuthResource,
128}
129
130impl ManagerClient {
131 pub async fn connect(auth: Auth) -> Result<Self, ManagerError> {
133 Self::builder(auth).connect().await
134 }
135
136 pub fn builder(auth: Auth) -> ManagerClientBuilder {
138 ManagerClientBuilder {
139 base_url: DEFAULT_BASE_URL.to_string(),
140 auth,
141 retry: RetryPolicy::default(),
142 }
143 }
144}
145
146pub struct ManagerClientBuilder {
148 base_url: String,
149 auth: Auth,
150 retry: RetryPolicy,
151}
152
153impl ManagerClientBuilder {
154 pub fn base_url(mut self, url: impl Into<String>) -> Self {
156 self.base_url = url.into();
157 self
158 }
159
160 pub fn retry(mut self, policy: RetryPolicy) -> Self {
162 self.retry = policy;
163 self
164 }
165
166 pub async fn connect(self) -> Result<ManagerClient, ManagerError> {
168 let base = self.base_url.trim_end_matches('/').to_string();
169
170 let mut headers = self.auth.static_headers();
171 let resolved_token = match &self.auth {
172 Auth::Password { user, pass } => Some(
173 fetch_token(
174 &base,
175 &[
176 ("grant_type", "password"),
177 ("username", user),
178 ("password", pass),
179 ("client_id", "manager"),
180 ],
181 )
182 .await?,
183 ),
184 Auth::ClientCredentials {
185 client_id,
186 client_secret,
187 } => Some(
188 fetch_token(
189 &base,
190 &[
191 ("grant_type", "client_credentials"),
192 ("client_id", client_id),
193 ("client_secret", client_secret),
194 ],
195 )
196 .await?,
197 ),
198 Auth::RefreshToken {
199 refresh_token,
200 client_id,
201 } => Some(
202 fetch_token(
203 &base,
204 &[
205 ("grant_type", "refresh_token"),
206 ("refresh_token", refresh_token),
207 ("client_id", client_id),
208 ],
209 )
210 .await?,
211 ),
212 Auth::Bearer { .. } => None,
213 };
214 if let Some(token) = resolved_token {
215 headers.insert(
216 AUTHORIZATION,
217 HeaderValue::from_str(&format!("Bearer {token}"))
218 .map_err(|e| ManagerError::Network(e.to_string()))?,
219 );
220 }
221
222 let http = reqwest::Client::builder()
223 .default_headers(headers)
224 .build()
225 .map_err(|e| ManagerError::Network(e.to_string()))?;
226
227 let user_agent =
228 Some(concat!("babelforce-manager-sdk-rust/", env!("CARGO_PKG_VERSION")).to_string());
229
230 let cfg = Arc::new(ManagerConfig {
231 base_path: base.clone(),
232 user_agent: user_agent.clone(),
233 client: http.clone(),
234 basic_auth: None,
235 oauth_access_token: None,
236 bearer_access_token: None,
237 api_key: None,
238 });
239
240 let user_cfg = Arc::new(UserConfig {
242 base_path: base.clone(),
243 user_agent: user_agent.clone(),
244 client: http.clone(),
245 basic_auth: None,
246 oauth_access_token: None,
247 bearer_access_token: None,
248 api_key: None,
249 });
250 let task_automation_cfg = Arc::new(TaskAutomationConfig {
251 base_path: base.clone(),
252 user_agent: user_agent.clone(),
253 client: http.clone(),
254 basic_auth: None,
255 oauth_access_token: None,
256 bearer_access_token: None,
257 api_key: None,
258 });
259 let task_schedule_cfg = Arc::new(TaskScheduleConfig {
260 base_path: base.clone(),
261 user_agent: user_agent.clone(),
262 client: http.clone(),
263 basic_auth: None,
264 oauth_access_token: None,
265 bearer_access_token: None,
266 api_key: None,
267 });
268 let auth_cfg = Arc::new(AuthConfig {
270 base_path: base,
271 user_agent,
272 client: http,
273 basic_auth: None,
274 oauth_access_token: None,
275 bearer_access_token: None,
276 api_key: None,
277 });
278
279 Ok(ManagerClient {
280 users: UsersResource {
281 cfg: cfg.clone(),
282 retry: self.retry.clone(),
283 },
284 agents: AgentsResource {
285 cfg: cfg.clone(),
286 retry: self.retry.clone(),
287 groups: AgentGroupsResource {
288 cfg: cfg.clone(),
289 retry: self.retry.clone(),
290 },
291 },
292 me: MeResource {
293 cfg: user_cfg,
294 retry: self.retry.clone(),
295 },
296 calls: CallsResource {
297 cfg: cfg.clone(),
298 retry: self.retry.clone(),
299 reporting: ReportingResource {
300 cfg: cfg.clone(),
301 retry: self.retry.clone(),
302 },
303 },
304 sms: SmsResource {
305 cfg: cfg.clone(),
306 retry: self.retry.clone(),
307 },
308 numbers: NumbersResource {
309 cfg: cfg.clone(),
310 retry: self.retry.clone(),
311 },
312 conferences: ConferencesResource {
313 cfg: cfg.clone(),
314 retry: self.retry.clone(),
315 },
316 queues: QueuesResource {
317 cfg: cfg.clone(),
318 retry: self.retry.clone(),
319 selections: QueueSelectionsResource {
320 cfg: cfg.clone(),
321 retry: self.retry.clone(),
322 },
323 },
324 recordings: RecordingsResource {
325 cfg: cfg.clone(),
326 retry: self.retry.clone(),
327 },
328 routing: RoutingResource {
329 cfg: cfg.clone(),
330 retry: self.retry.clone(),
331 },
332 triggers: TriggersResource {
333 cfg: cfg.clone(),
334 retry: self.retry.clone(),
335 },
336 automations: AutomationsResource {
337 cfg: cfg.clone(),
338 retry: self.retry.clone(),
339 },
340 integrations: IntegrationsResource {
341 cfg: cfg.clone(),
342 retry: self.retry.clone(),
343 },
344 outbound: OutboundResource {
345 cfg: cfg.clone(),
346 retry: self.retry.clone(),
347 },
348 phonebook: PhonebookResource {
349 cfg: cfg.clone(),
350 retry: self.retry.clone(),
351 },
352 campaigns: CampaignsResource {
353 cfg: cfg.clone(),
354 retry: self.retry.clone(),
355 },
356 business_hours: BusinessHoursResource {
357 cfg: cfg.clone(),
358 retry: self.retry.clone(),
359 },
360 calendars: CalendarsResource {
361 cfg: cfg.clone(),
362 retry: self.retry.clone(),
363 },
364 conversations: ConversationsResource {
365 cfg: cfg.clone(),
366 retry: self.retry.clone(),
367 },
368 dashboards: DashboardsResource {
369 cfg: cfg.clone(),
370 retry: self.retry.clone(),
371 },
372 dialer: DialerResource {
373 cfg: cfg.clone(),
374 retry: self.retry.clone(),
375 behaviours: DialerBehavioursResource {
376 cfg: cfg.clone(),
377 retry: self.retry.clone(),
378 },
379 },
380 sessions: SessionsResource {
381 cfg: cfg.clone(),
382 retry: self.retry.clone(),
383 },
384 prompts: PromptsResource {
385 cfg: cfg.clone(),
386 retry: self.retry.clone(),
387 },
388 babeldesk: BabeldeskResource {
389 cfg: cfg.clone(),
390 retry: self.retry.clone(),
391 widgets: BabeldeskWidgetsResource {
392 cfg: cfg.clone(),
393 retry: self.retry.clone(),
394 },
395 },
396 events: EventsResource {
397 cfg: cfg.clone(),
398 retry: self.retry.clone(),
399 },
400 expressions: ExpressionsResource {
401 cfg: cfg.clone(),
402 retry: self.retry.clone(),
403 },
404 files: FilesResource {
405 cfg: cfg.clone(),
406 retry: self.retry.clone(),
407 },
408 logs: LogsResource {
409 cfg: cfg.clone(),
410 retry: self.retry.clone(),
411 },
412 metrics: MetricsResource {
413 cfg: cfg.clone(),
414 retry: self.retry.clone(),
415 },
416 system: SystemResource {
417 cfg: cfg.clone(),
418 retry: self.retry.clone(),
419 },
420 settings: SettingsResource {
421 cfg: cfg.clone(),
422 retry: self.retry.clone(),
423 },
424 applications: ApplicationsResource {
425 cfg: cfg.clone(),
426 retry: self.retry.clone(),
427 local_automations: LocalAutomationsResource {
428 cfg: cfg.clone(),
429 retry: self.retry.clone(),
430 },
431 },
432 tasks: TasksResource {
433 cfg: task_automation_cfg.clone(),
434 retry: self.retry.clone(),
435 scripts: TaskScriptsResource {
436 cfg: task_automation_cfg.clone(),
437 retry: self.retry.clone(),
438 },
439 secrets: TaskSecretsResource {
440 cfg: task_automation_cfg.clone(),
441 retry: self.retry.clone(),
442 },
443 selection_config: TaskSelectionConfigResource {
444 cfg: task_automation_cfg.clone(),
445 retry: self.retry.clone(),
446 },
447 metrics: TaskMetricsResource {
448 cfg: task_automation_cfg.clone(),
449 retry: self.retry.clone(),
450 },
451 },
452 schedules: TaskSchedulesResource {
453 cfg: task_schedule_cfg,
454 retry: self.retry.clone(),
455 },
456 auth: AuthResource {
457 cfg: auth_cfg,
458 retry: self.retry.clone(),
459 },
460 })
461 }
462}
463
464async fn fetch_token(base: &str, params: &[(&str, &str)]) -> Result<String, ManagerError> {
467 #[derive(serde::Deserialize)]
468 struct Token {
469 access_token: String,
470 }
471 let resp = reqwest::Client::new()
472 .post(format!("{base}/oauth/token"))
473 .form(params)
474 .send()
475 .await
476 .map_err(|e| ManagerError::Network(e.to_string()))?;
477 let status = resp.status();
478 let body = resp
479 .text()
480 .await
481 .map_err(|e| ManagerError::Network(e.to_string()))?;
482 if !status.is_success() {
483 return Err(ManagerError::from_response(status.as_u16(), body));
484 }
485 let token: Token =
486 serde_json::from_str(&body).map_err(|e| ManagerError::Decode(e.to_string()))?;
487 Ok(token.access_token)
488}