use std::time::Duration;
use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, USER_AGENT};
use crate::VERSION;
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug, Clone)]
pub struct Client {
pub(crate) api_key: String,
pub(crate) base_url: String,
pub(crate) http: reqwest::Client,
}
impl Client {
pub fn new(api_key: impl Into<String>) -> Self {
ClientBuilder::new(api_key)
.build()
.expect("default reqwest::Client should always build")
}
pub fn builder(api_key: impl Into<String>) -> ClientBuilder {
ClientBuilder::new(api_key)
}
pub fn api_key(&self) -> &str {
&self.api_key
}
pub fn base_url(&self) -> &str {
&self.base_url
}
}
#[derive(Debug)]
pub struct ClientBuilder {
api_key: String,
base_url: String,
timeout: Duration,
http: Option<reqwest::Client>,
}
impl ClientBuilder {
pub fn new(api_key: impl Into<String>) -> Self {
Self {
api_key: api_key.into(),
base_url: crate::DEFAULT_BASE_URL.to_string(),
timeout: DEFAULT_TIMEOUT,
http: None,
}
}
pub fn base_url(mut self, url: impl Into<String>) -> Self {
self.base_url = url.into();
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn http_client(mut self, http: reqwest::Client) -> Self {
self.http = Some(http);
self
}
pub fn build(self) -> Result<Client, reqwest::Error> {
let http = match self.http {
Some(h) => h,
None => {
let mut headers = HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
headers.insert(
USER_AGENT,
HeaderValue::from_str(&format!("unirate-rust/{VERSION}"))
.expect("user agent must be ASCII"),
);
reqwest::Client::builder()
.timeout(self.timeout)
.default_headers(headers)
.build()?
}
};
let base_url = self.base_url.trim_end_matches('/').to_string();
Ok(Client {
api_key: self.api_key,
base_url,
http,
})
}
}