monoio_http_client/client/
mod.rs

1pub mod connection;
2pub mod connector;
3pub mod key;
4pub mod pool;
5pub mod unified;
6
7use std::rc::Rc;
8
9use bytes::Bytes;
10use http::HeaderMap;
11use monoio_http::common::{
12    body::{Body, HttpBody},
13    error::HttpError,
14    request::Request,
15    response::Response,
16};
17
18use self::{
19    connector::{Connector, PooledConnector},
20    key::Key,
21    pool::PooledConnection,
22    unified::{UnifiedTransportConnection, UnifiedTransportConnector},
23};
24use crate::request::ClientRequest;
25
26#[derive(Debug)]
27pub struct ClientInner<C> {
28    cfg: ClientConfig,
29    connector: PooledConnector<C, Key, UnifiedTransportConnection>,
30}
31
32pub struct Client<C = UnifiedTransportConnector> {
33    shared: Rc<ClientInner<C>>,
34}
35
36// Impl Clone manually because C does not have to be Clone
37impl<C> Clone for Client<C> {
38    fn clone(&self) -> Self {
39        Self {
40            shared: self.shared.clone(),
41        }
42    }
43}
44
45#[derive(Default, Clone, PartialEq, Eq)]
46pub enum Proto {
47    #[default]
48    Http1, // HTTP1_1 only client
49    Http2, // HTTP2 only client
50    Auto,  // Uses version header in request
51}
52
53// HTTP1 & HTTP2 Connection specific.
54#[derive(Default, Clone)]
55pub struct ConnectionConfig {
56    pub proto: Proto,
57    h2_builder: monoio_http::h2::client::Builder,
58}
59
60// Global config applicable to
61// all connections maintained by client
62#[derive(Default, Clone)]
63pub struct ClientGlobalConfig {
64    max_idle_connections: usize,
65}
66
67#[derive(Default, Clone)]
68pub struct Builder {
69    connection_config: ConnectionConfig,
70    global_config: ClientGlobalConfig,
71}
72
73impl Builder {
74    pub fn new() -> Self {
75        Self::default()
76    }
77
78    pub fn http1_client(mut self) -> Self {
79        self.connection_config.proto = Proto::Http1;
80        self
81    }
82
83    pub fn http2_client(mut self) -> Self {
84        self.connection_config.proto = Proto::Http2;
85        self
86    }
87
88    pub fn http_auto(mut self) -> Self {
89        self.connection_config.proto = Proto::Auto;
90        self
91    }
92
93    pub fn max_idle_connections(mut self, conns: usize) -> Self {
94        self.global_config.max_idle_connections = conns;
95        self
96    }
97
98    pub fn http2_max_frame_size(mut self, sz: u32) -> Self {
99        self.connection_config.h2_builder.max_frame_size(sz);
100        self
101    }
102
103    pub fn http2_max_send_buf_size(mut self, sz: usize) -> Self {
104        self.connection_config.h2_builder.max_send_buffer_size(sz);
105        self
106    }
107
108    pub fn http2_max_concurrent_reset_streams(mut self, max: usize) -> Self {
109        self.connection_config.h2_builder.max_send_buffer_size(max);
110        self
111    }
112
113    pub fn http2_initial_stream_window_size(mut self, size: u32) -> Self {
114        self.connection_config.h2_builder.initial_window_size(size);
115        self
116    }
117
118    pub fn http2_initial_connection_window_size(mut self, size: u32) -> Self {
119        self.connection_config
120            .h2_builder
121            .initial_connection_window_size(size);
122        self
123    }
124
125    pub fn http2_max_concurrent_streams(mut self, max: u32) -> Self {
126        self.connection_config
127            .h2_builder
128            .max_concurrent_streams(max);
129        self
130    }
131
132    pub fn build(self) -> Client {
133        Client::new(self.global_config, self.connection_config)
134    }
135
136    pub fn build_with_connector<C>(self, connector: C) -> Client<C> {
137        let shared = Rc::new(ClientInner {
138            cfg: ClientConfig::default(),
139            connector: PooledConnector::new(self.global_config, self.connection_config, connector),
140        });
141        Client { shared }
142    }
143}
144
145#[derive(Default, Clone, Debug)]
146pub struct ClientConfig {
147    default_headers: Rc<HeaderMap>,
148}
149
150impl Default for Client {
151    fn default() -> Self {
152        Builder::default().build()
153    }
154}
155
156impl Client {
157    fn new(g_config: ClientGlobalConfig, c_config: ConnectionConfig) -> Client {
158        let shared = Rc::new(ClientInner {
159            cfg: ClientConfig::default(),
160            connector: PooledConnector::new_default(g_config, c_config),
161        });
162        Client { shared }
163    }
164
165    pub fn builder() -> Builder {
166        Builder::new()
167    }
168}
169
170macro_rules! http_method {
171    ($fn: ident, $method: expr) => {
172        pub fn $fn<U>(&self, uri: U) -> ClientRequest<C>
173        where
174            http::Uri: TryFrom<U>,
175            <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
176        {
177            self.request($method, uri)
178        }
179    };
180}
181
182impl<C> Client<C> {
183    http_method!(get, http::Method::GET);
184    http_method!(post, http::Method::POST);
185    http_method!(put, http::Method::PUT);
186    http_method!(patch, http::Method::PATCH);
187    http_method!(delete, http::Method::DELETE);
188    http_method!(head, http::Method::HEAD);
189
190    pub fn request<M, U>(&self, method: M, uri: U) -> ClientRequest<C>
191    where
192        http::Method: TryFrom<M>,
193        <http::Method as TryFrom<M>>::Error: Into<http::Error>,
194        http::Uri: TryFrom<U>,
195        <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
196    {
197        let mut req = ClientRequest::<C>::new(self.clone())
198            .method(method)
199            .uri(uri);
200        for (key, value) in self.shared.cfg.default_headers.iter() {
201            req = req.header(key, value);
202        }
203        req
204    }
205
206    pub async fn send_request<B: Body<Data = Bytes, Error = HttpError> + 'static>(
207        &self,
208        req: Request<B>,
209    ) -> crate::Result<Response<HttpBody>>
210    where
211        PooledConnector<C, Key, UnifiedTransportConnection>: Connector<
212            Key,
213            Connection = PooledConnection<Key, UnifiedTransportConnection>,
214            Error = crate::Error,
215        >,
216    {
217        let mut key: Key = req.uri().try_into()?;
218        key.version = req.version();
219        let conn = self.shared.connector.connect(key).await?;
220        conn.send_request(req).await
221    }
222}