use std::{
fmt,
sync::{atomic::AtomicU64, Arc},
time::Duration,
};
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use crate::{error::HttpClientError, http_client::HttpClient};
#[derive(Debug)]
pub struct HttpClientBuilder {
pub(crate) headers: HeaderMap,
timeout: Option<Duration>,
connect_timeout: Option<Duration>,
}
impl Default for HttpClientBuilder {
fn default() -> Self {
Self::new()
}
}
impl HttpClientBuilder {
pub fn new() -> Self {
Self {
headers: HeaderMap::new(),
timeout: None,
connect_timeout: None,
}
}
pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> Self
where
U: fmt::Display,
P: fmt::Display,
{
let mut basic_auth = "Basic ".to_string();
let auth = if let Some(password) = password {
base64::encode(format!("{}:{}", username, password))
} else {
base64::encode(format!("{}:", username))
};
basic_auth.push_str(&auth);
let value = HeaderValue::from_str(&basic_auth).expect("basic auth header value");
self.header(header::AUTHORIZATION, value)
}
pub fn bearer_auth<T>(self, token: T) -> Self
where
T: fmt::Display,
{
let bearer_auth = format!("Bearer {}", token);
let value = HeaderValue::from_str(&bearer_auth).expect("bearer auth header value");
self.header(header::AUTHORIZATION, value)
}
pub fn header(mut self, name: HeaderName, value: HeaderValue) -> Self {
self.headers.insert(name, value);
self
}
pub fn headers(mut self, headers: HeaderMap) -> Self {
self.headers.extend(headers);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[cfg(feature = "http-tokio")]
pub fn connect_timeout(mut self, timeout: Duration) -> Self {
self.connect_timeout = Some(timeout);
self
}
#[cfg(feature = "http-async-std")]
pub fn build<U: Into<String>>(self, url: U) -> Result<HttpClient, HttpClientError> {
Ok(HttpClient {
url: url.into(),
id: Arc::new(AtomicU64::new(1)),
client: surf::Client::new(),
headers: self.headers,
timeout: self.timeout,
})
}
#[cfg(feature = "http-tokio")]
pub fn build<U: Into<String>>(self, url: U) -> Result<HttpClient, HttpClientError> {
let builder = reqwest::Client::builder().default_headers(self.headers);
let builder = if let Some(timeout) = self.timeout {
builder.timeout(timeout)
} else {
builder
};
let builder = if let Some(timeout) = self.connect_timeout {
builder.connect_timeout(timeout)
} else {
builder
};
let client = builder.build()?;
Ok(HttpClient {
url: url.into(),
id: Arc::new(AtomicU64::new(1)),
client,
})
}
}