use std::sync::Arc;
use reqwest::header::{HeaderValue, AUTHORIZATION};
use crate::auth::Auth;
use crate::error::ManagerError;
use crate::gen::auth::apis::configuration::Configuration as AuthConfig;
use crate::gen::manager::apis::configuration::Configuration as ManagerConfig;
use crate::gen::task_automation::apis::configuration::Configuration as TaskAutomationConfig;
use crate::gen::task_schedule::apis::configuration::Configuration as TaskScheduleConfig;
use crate::gen::user::apis::configuration::Configuration as UserConfig;
use crate::resources::agents::{AgentGroupsResource, AgentsResource};
use crate::resources::applications::{ApplicationsResource, LocalAutomationsResource};
use crate::resources::auth::AuthResource;
use crate::resources::automations::AutomationsResource;
use crate::resources::babeldesk::{BabeldeskResource, BabeldeskWidgetsResource};
use crate::resources::businesshours::BusinessHoursResource;
use crate::resources::calendars::CalendarsResource;
use crate::resources::calls::{CallsResource, ReportingResource};
use crate::resources::campaigns::CampaignsResource;
use crate::resources::conferences::ConferencesResource;
use crate::resources::conversations::ConversationsResource;
use crate::resources::dashboards::DashboardsResource;
use crate::resources::dialer::{DialerBehavioursResource, DialerResource};
use crate::resources::events::EventsResource;
use crate::resources::expressions::ExpressionsResource;
use crate::resources::files::FilesResource;
use crate::resources::integrations::IntegrationsResource;
use crate::resources::logs::LogsResource;
use crate::resources::me::MeResource;
use crate::resources::metrics::MetricsResource;
use crate::resources::numbers::NumbersResource;
use crate::resources::outbound::OutboundResource;
use crate::resources::phonebook::PhonebookResource;
use crate::resources::prompts::PromptsResource;
use crate::resources::queues::{QueueSelectionsResource, QueuesResource};
use crate::resources::recordings::RecordingsResource;
use crate::resources::routing::RoutingResource;
use crate::resources::schedules::TaskSchedulesResource;
use crate::resources::sessions::SessionsResource;
use crate::resources::settings::SettingsResource;
use crate::resources::sms::SmsResource;
use crate::resources::system::SystemResource;
use crate::resources::tasks::{
TaskMetricsResource, TaskScriptsResource, TaskSecretsResource, TaskSelectionConfigResource,
TasksResource,
};
use crate::resources::triggers::TriggersResource;
use crate::resources::users::UsersResource;
use crate::retry::RetryPolicy;
pub const DEFAULT_BASE_URL: &str = "https://services.babelforce.com";
pub struct ManagerClient {
pub users: UsersResource,
pub agents: AgentsResource,
pub me: MeResource,
pub calls: CallsResource,
pub sms: SmsResource,
pub numbers: NumbersResource,
pub conferences: ConferencesResource,
pub queues: QueuesResource,
pub recordings: RecordingsResource,
pub routing: RoutingResource,
pub triggers: TriggersResource,
pub automations: AutomationsResource,
pub integrations: IntegrationsResource,
pub outbound: OutboundResource,
pub phonebook: PhonebookResource,
pub campaigns: CampaignsResource,
pub business_hours: BusinessHoursResource,
pub calendars: CalendarsResource,
pub conversations: ConversationsResource,
pub dashboards: DashboardsResource,
pub dialer: DialerResource,
pub sessions: SessionsResource,
pub prompts: PromptsResource,
pub babeldesk: BabeldeskResource,
pub events: EventsResource,
pub expressions: ExpressionsResource,
pub files: FilesResource,
pub logs: LogsResource,
pub metrics: MetricsResource,
pub system: SystemResource,
pub settings: SettingsResource,
pub applications: ApplicationsResource,
pub tasks: TasksResource,
pub schedules: TaskSchedulesResource,
pub auth: AuthResource,
}
impl ManagerClient {
pub async fn connect(auth: Auth) -> Result<Self, ManagerError> {
Self::builder(auth).connect().await
}
pub fn builder(auth: Auth) -> ManagerClientBuilder {
ManagerClientBuilder {
base_url: DEFAULT_BASE_URL.to_string(),
auth,
retry: RetryPolicy::default(),
}
}
}
pub struct ManagerClientBuilder {
base_url: String,
auth: Auth,
retry: RetryPolicy,
}
impl ManagerClientBuilder {
pub fn base_url(mut self, url: impl Into<String>) -> Self {
self.base_url = url.into();
self
}
pub fn retry(mut self, policy: RetryPolicy) -> Self {
self.retry = policy;
self
}
pub async fn connect(self) -> Result<ManagerClient, ManagerError> {
let base = self.base_url.trim_end_matches('/').to_string();
let mut headers = self.auth.static_headers();
let resolved_token = match &self.auth {
Auth::Password { user, pass } => Some(
fetch_token(
&base,
&[
("grant_type", "password"),
("username", user),
("password", pass),
("client_id", "manager"),
],
)
.await?,
),
Auth::ClientCredentials {
client_id,
client_secret,
} => Some(
fetch_token(
&base,
&[
("grant_type", "client_credentials"),
("client_id", client_id),
("client_secret", client_secret),
],
)
.await?,
),
Auth::RefreshToken {
refresh_token,
client_id,
} => Some(
fetch_token(
&base,
&[
("grant_type", "refresh_token"),
("refresh_token", refresh_token),
("client_id", client_id),
],
)
.await?,
),
Auth::Bearer { .. } => None,
};
if let Some(token) = resolved_token {
headers.insert(
AUTHORIZATION,
HeaderValue::from_str(&format!("Bearer {token}"))
.map_err(|e| ManagerError::Network(e.to_string()))?,
);
}
let http = reqwest::Client::builder()
.default_headers(headers)
.build()
.map_err(|e| ManagerError::Network(e.to_string()))?;
let user_agent =
Some(concat!("babelforce-manager-sdk-rust/", env!("CARGO_PKG_VERSION")).to_string());
let cfg = Arc::new(ManagerConfig {
base_path: base.clone(),
user_agent: user_agent.clone(),
client: http.clone(),
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
});
let user_cfg = Arc::new(UserConfig {
base_path: base.clone(),
user_agent: user_agent.clone(),
client: http.clone(),
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
});
let task_automation_cfg = Arc::new(TaskAutomationConfig {
base_path: base.clone(),
user_agent: user_agent.clone(),
client: http.clone(),
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
});
let task_schedule_cfg = Arc::new(TaskScheduleConfig {
base_path: base.clone(),
user_agent: user_agent.clone(),
client: http.clone(),
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
});
let auth_cfg = Arc::new(AuthConfig {
base_path: base,
user_agent,
client: http,
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
});
Ok(ManagerClient {
users: UsersResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
agents: AgentsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
groups: AgentGroupsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
},
me: MeResource {
cfg: user_cfg,
retry: self.retry.clone(),
},
calls: CallsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
reporting: ReportingResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
},
sms: SmsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
numbers: NumbersResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
conferences: ConferencesResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
queues: QueuesResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
selections: QueueSelectionsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
},
recordings: RecordingsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
routing: RoutingResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
triggers: TriggersResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
automations: AutomationsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
integrations: IntegrationsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
outbound: OutboundResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
phonebook: PhonebookResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
campaigns: CampaignsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
business_hours: BusinessHoursResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
calendars: CalendarsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
conversations: ConversationsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
dashboards: DashboardsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
dialer: DialerResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
behaviours: DialerBehavioursResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
},
sessions: SessionsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
prompts: PromptsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
babeldesk: BabeldeskResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
widgets: BabeldeskWidgetsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
},
events: EventsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
expressions: ExpressionsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
files: FilesResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
logs: LogsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
metrics: MetricsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
system: SystemResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
settings: SettingsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
applications: ApplicationsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
local_automations: LocalAutomationsResource {
cfg: cfg.clone(),
retry: self.retry.clone(),
},
},
tasks: TasksResource {
cfg: task_automation_cfg.clone(),
retry: self.retry.clone(),
scripts: TaskScriptsResource {
cfg: task_automation_cfg.clone(),
retry: self.retry.clone(),
},
secrets: TaskSecretsResource {
cfg: task_automation_cfg.clone(),
retry: self.retry.clone(),
},
selection_config: TaskSelectionConfigResource {
cfg: task_automation_cfg.clone(),
retry: self.retry.clone(),
},
metrics: TaskMetricsResource {
cfg: task_automation_cfg.clone(),
retry: self.retry.clone(),
},
},
schedules: TaskSchedulesResource {
cfg: task_schedule_cfg,
retry: self.retry.clone(),
},
auth: AuthResource {
cfg: auth_cfg,
retry: self.retry.clone(),
},
})
}
}
async fn fetch_token(base: &str, params: &[(&str, &str)]) -> Result<String, ManagerError> {
#[derive(serde::Deserialize)]
struct Token {
access_token: String,
}
let resp = reqwest::Client::new()
.post(format!("{base}/oauth/token"))
.form(params)
.send()
.await
.map_err(|e| ManagerError::Network(e.to_string()))?;
let status = resp.status();
let body = resp
.text()
.await
.map_err(|e| ManagerError::Network(e.to_string()))?;
if !status.is_success() {
return Err(ManagerError::from_response(status.as_u16(), body));
}
let token: Token =
serde_json::from_str(&body).map_err(|e| ManagerError::Decode(e.to_string()))?;
Ok(token.access_token)
}