use std::net::SocketAddr;
use crate::error::HttpError;
use crate::h1_conn::H1Conn;
use crate::h2_conn::H2AsyncConn;
use crate::request::RequestBuilder;
use crate::response::Response;
use crate::streaming::StreamingResponse;
enum ConnectionInner {
H2(Box<H2AsyncConn>),
H1(H1Conn),
}
pub struct HttpClient {
inner: ConnectionInner,
host: String,
}
impl HttpClient {
pub async fn connect_h2(addr: SocketAddr, host: &str) -> Result<Self, HttpError> {
let h2 = H2AsyncConn::connect(addr, host).await?;
Ok(Self {
inner: ConnectionInner::H2(Box::new(h2)),
host: host.to_string(),
})
}
pub async fn connect_h2_with_timeout(
addr: SocketAddr,
host: &str,
timeout_ms: u64,
) -> Result<Self, HttpError> {
let h2 = H2AsyncConn::connect_with_timeout(addr, host, timeout_ms).await?;
Ok(Self {
inner: ConnectionInner::H2(Box::new(h2)),
host: host.to_string(),
})
}
pub async fn connect_h1(addr: SocketAddr, host: &str) -> Result<Self, HttpError> {
let h1 = H1Conn::connect_tls(addr, host).await?;
Ok(Self {
inner: ConnectionInner::H1(h1),
host: host.to_string(),
})
}
pub async fn connect_h1_plain(addr: SocketAddr, host: &str) -> Result<Self, HttpError> {
let h1 = H1Conn::connect_plain(addr, host).await?;
Ok(Self {
inner: ConnectionInner::H1(h1),
host: host.to_string(),
})
}
pub fn get(&mut self, path: &str) -> RequestBuilder<'_> {
RequestBuilder::new(self, "GET", path)
}
pub fn post(&mut self, path: &str) -> RequestBuilder<'_> {
RequestBuilder::new(self, "POST", path)
}
pub fn put(&mut self, path: &str) -> RequestBuilder<'_> {
RequestBuilder::new(self, "PUT", path)
}
pub fn delete(&mut self, path: &str) -> RequestBuilder<'_> {
RequestBuilder::new(self, "DELETE", path)
}
pub(crate) async fn send_request(
&mut self,
method: &str,
path: &str,
extra_headers: &[(&str, &str)],
body: Option<&[u8]>,
) -> Result<Response, HttpError> {
match &mut self.inner {
ConnectionInner::H2(h2) => {
h2.send_request(method, path, &self.host, extra_headers, body)
.await
}
ConnectionInner::H1(h1) => h1.send_request(method, path, extra_headers, body).await,
}
}
pub(crate) async fn send_request_streaming(
&mut self,
method: &str,
path: &str,
extra_headers: &[(&str, &str)],
body: Option<&[u8]>,
) -> Result<StreamingResponse<'_>, HttpError> {
match &mut self.inner {
ConnectionInner::H2(h2) => {
let stream = h2
.send_request_streaming(method, path, &self.host, extra_headers, body)
.await?;
Ok(StreamingResponse::H2(stream))
}
ConnectionInner::H1(h1) => {
let stream = h1
.send_request_streaming(method, path, extra_headers, body)
.await?;
Ok(StreamingResponse::H1(stream))
}
}
}
pub fn close(&self) {
match &self.inner {
ConnectionInner::H2(h2) => h2.close(),
ConnectionInner::H1(h1) => h1.close(),
}
}
}