use std::convert::TryInto;
use std::result::Result as StdResult;
use crate::client::HttpClient;
use crate::error::{Error, Result};
use isahc::http::{
self,
header::{HeaderMap, HeaderName, HeaderValue},
};
use url::Url;
#[derive(Debug)]
struct HttpClientBuilderInner {
url: Url,
token: Option<String>,
additional_headers: HeaderMap,
}
#[derive(Debug)]
pub struct HttpClientBuilder {
inner: Result<HttpClientBuilderInner>,
}
trait ResultExt<T, E> {
fn err_into<U>(self) -> StdResult<T, U>
where
E: Into<U>;
fn and_then_mut<F>(&mut self, op: F)
where
F: FnOnce(&mut T) -> StdResult<(), E>;
}
impl<T, E> ResultExt<T, E> for StdResult<T, E> {
fn err_into<U>(self) -> StdResult<T, U>
where
E: Into<U>,
{
self.map_err(Into::into)
}
fn and_then_mut<F>(&mut self, f: F)
where
F: FnOnce(&mut T) -> StdResult<(), E>,
{
if let Ok(x) = self {
if let Err(e) = f(x) {
*self = Err(e);
}
}
}
}
impl HttpClientBuilder {
pub fn new<T>(url: T) -> Self
where
T: TryInto<Url>,
T::Error: Into<Error>,
{
let inner = url.try_into().err_into().map(|url| HttpClientBuilderInner {
url,
token: None,
additional_headers: HeaderMap::new(),
});
HttpClientBuilder { inner }
}
pub fn with_host<S>(host: S) -> Self
where
S: AsRef<str>,
{
let url = format!("https://{}/api/", host.as_ref());
HttpClientBuilder::new(url.as_str())
}
pub fn header<K, V>(mut self, key: K, value: V) -> Self
where
K: TryInto<HeaderName>,
V: TryInto<HeaderValue>,
K::Error: Into<http::Error>,
V::Error: Into<http::Error>,
{
self.inner.and_then_mut(|inner| {
let result = key.try_into().err_into().and_then(|key| {
let value = value.try_into().err_into()?;
Ok((key, value))
});
match result {
Ok((key, value)) => {
inner.additional_headers.insert(key, value);
Ok(())
}
Err(e) => Err(Error::Network(isahc::Error::InvalidHttpFormat(e))),
}
});
self
}
pub fn token<S>(mut self, token: S) -> Self
where
S: Into<String>,
{
self.inner.and_then_mut(|inner| {
inner.token = Some(token.into());
Ok(())
});
self
}
pub fn build(self) -> Result<HttpClient> {
self.inner.and_then(|inner| {
Ok(HttpClient {
url: inner.url,
token: inner.token,
client: isahc::HttpClientBuilder::new()
.default_headers(&inner.additional_headers)
.build()?,
})
})
}
}