use crate::{connection, error, request, response};
use std::str::FromStr;
use std::{rc, time};
#[derive(Clone, Debug)]
pub struct Client {
pool: rc::Rc<connection::Pool>,
}
impl Client {
pub(crate) fn new(pool: rc::Rc<connection::Pool>) -> Self {
Self { pool }
}
pub fn get(&self, url: impl AsRef<str>) -> Result<request::Builder, Box<error::Error>> {
self.request(http_types::Method::Get, url)
}
pub fn post(&self, url: impl AsRef<str>) -> Result<request::Builder, Box<error::Error>> {
self.request(http_types::Method::Post, url)
}
pub fn put(&self, url: impl AsRef<str>) -> Result<request::Builder, Box<error::Error>> {
self.request(http_types::Method::Put, url)
}
pub fn patch(&self, url: impl AsRef<str>) -> Result<request::Builder, Box<error::Error>> {
self.request(http_types::Method::Patch, url)
}
pub fn delete(&self, url: impl AsRef<str>) -> Result<request::Builder, Box<error::Error>> {
self.request(http_types::Method::Delete, url)
}
pub fn head(&self, url: impl AsRef<str>) -> Result<request::Builder, Box<error::Error>> {
self.request(http_types::Method::Head, url)
}
pub fn request(
&self,
method: impl AsRef<str>,
url: impl AsRef<str>,
) -> Result<request::Builder, Box<error::Error>> {
let url =
http_types::Url::parse(url.as_ref()).map_err(|e| Box::new(error::Error::URL(e)))?;
let method =
http_types::Method::from_str(method.as_ref()).map_err(Box::new(error::Error::HTTP))?;
Ok(request::Builder::new(
request::Request::new(method, url),
self.clone(),
))
}
pub fn execute(
&self,
request: request::Request,
) -> Result<response::Response, Box<error::Error>> {
let host = request.url().host_str().ok_or(error::Error::EmptyHost)?;
let port = if let Some(v) = request.url().port() {
v
} else {
match request.url().scheme() {
"http" => 80,
"https" => 443,
_ => return Err(Box::new(error::Error::UnsupportedSchema)),
}
};
let mut connection = self.pool.get(host, port)?;
connection.execute(request)
}
}
#[derive(Clone, Debug)]
pub struct Builder {
max_conns: Option<usize>,
conn_ttl: Option<time::Duration>,
connect_timeout: Option<time::Duration>,
acquire_timeout: Option<time::Duration>,
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}
impl Builder {
pub fn new() -> Self {
Self {
max_conns: None,
conn_ttl: None,
connect_timeout: None,
acquire_timeout: None,
}
}
pub fn pool_max_conns(mut self, max_conns: usize) -> Self {
self.max_conns = Some(max_conns);
self
}
pub fn pool_conn_ttl(mut self, ttl: time::Duration) -> Self {
self.conn_ttl = Some(ttl);
self
}
pub fn pool_connect_timeout(mut self, timeout: time::Duration) -> Self {
self.connect_timeout = Some(timeout);
self
}
pub fn pool_acquire_timeout(mut self, timeout: time::Duration) -> Self {
self.acquire_timeout = Some(timeout);
self
}
pub fn build(self) -> Client {
let pool = connection::Pool::new(
self.max_conns.unwrap_or(100),
self.conn_ttl.unwrap_or(time::Duration::from_secs(120)),
self.connect_timeout.unwrap_or(time::Duration::from_secs(3)),
self.acquire_timeout
.unwrap_or(time::Duration::from_secs(60)),
);
Client::new(rc::Rc::new(pool))
}
}