monoio_http_client/client/
mod.rs1pub 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
36impl<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, Http2, Auto, }
52
53#[derive(Default, Clone)]
55pub struct ConnectionConfig {
56 pub proto: Proto,
57 h2_builder: monoio_http::h2::client::Builder,
58}
59
60#[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}