use std::time::Duration;
use reqwest::header::CONTENT_TYPE;
use serde_json::Map;
use url::Url;
use crate::{error::WhmcsError, models::WhmcsRawResponse};
#[derive(Debug)]
pub struct WhmcsClient {
client: reqwest::Client,
url: Url,
api_identifier: String,
api_secret: String,
timeout: u64,
}
impl WhmcsClient {
#[must_use]
pub fn new(url: Url, api_identifier: String, api_secret: String, timeout: u64) -> Self {
Self {
client: reqwest::Client::new(),
url,
api_identifier,
api_secret,
timeout,
}
}
pub async fn request<P, T>(&self, action: &str, params: P) -> Result<T, WhmcsError>
where
P: serde::Serialize,
T: serde::de::DeserializeOwned,
{
let mut request_body =
serde_json::to_value(params).map_err(WhmcsError::SerializationError)?;
if request_body.is_null() {
request_body = serde_json::Value::Object(Map::new());
}
if let Some(obj) = request_body.as_object_mut() {
obj.insert("action".to_string(), action.into());
obj.insert("identifier".to_string(), self.api_identifier.clone().into());
obj.insert("secret".to_string(), self.api_secret.clone().into());
obj.insert("responsetype".to_string(), "json".into());
}
let response_text = self
.client
.post(self.url.as_str())
.header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.form(&request_body)
.timeout(Duration::from_secs(self.timeout))
.send()
.await
.map_err(WhmcsError::RequestError)?
.text()
.await
.map_err(WhmcsError::RequestError)?;
match serde_json::from_str::<WhmcsRawResponse<T>>(&response_text)
.map_err(WhmcsError::SerializationError)?
{
WhmcsRawResponse::Success(data) => Ok(data),
WhmcsRawResponse::Error { message } => Err(WhmcsError::ApiError(message)),
}
}
}