async_jsonrpc_client/http_client/
builder.rs1use std::{
2 fmt,
3 sync::{atomic::AtomicU64, Arc},
4 time::Duration,
5};
6
7use http::header::{self, HeaderMap, HeaderName, HeaderValue};
8
9use crate::{error::HttpClientError, http_client::HttpClient};
10
11#[derive(Debug)]
13pub struct HttpClientBuilder {
14 pub(crate) headers: HeaderMap,
15 timeout: Option<Duration>,
16 connect_timeout: Option<Duration>,
17}
18
19impl Default for HttpClientBuilder {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl HttpClientBuilder {
26 pub fn new() -> Self {
30 Self {
31 headers: HeaderMap::new(),
32 timeout: None,
33 connect_timeout: None,
34 }
35 }
36
37 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> Self
43 where
44 U: fmt::Display,
45 P: fmt::Display,
46 {
47 let mut basic_auth = "Basic ".to_string();
48 let auth = if let Some(password) = password {
49 base64::encode(format!("{}:{}", username, password))
50 } else {
51 base64::encode(format!("{}:", username))
52 };
53 basic_auth.push_str(&auth);
54 let value = HeaderValue::from_str(&basic_auth).expect("basic auth header value");
55 self.header(header::AUTHORIZATION, value)
56 }
57
58 pub fn bearer_auth<T>(self, token: T) -> Self
60 where
61 T: fmt::Display,
62 {
63 let bearer_auth = format!("Bearer {}", token);
64 let value = HeaderValue::from_str(&bearer_auth).expect("bearer auth header value");
65 self.header(header::AUTHORIZATION, value)
66 }
67
68 pub fn header(mut self, name: HeaderName, value: HeaderValue) -> Self {
70 self.headers.insert(name, value);
71 self
72 }
73
74 pub fn headers(mut self, headers: HeaderMap) -> Self {
76 self.headers.extend(headers);
77 self
78 }
79
80 pub fn timeout(mut self, timeout: Duration) -> Self {
91 self.timeout = Some(timeout);
92 self
93 }
94
95 #[cfg(feature = "http-tokio")]
99 pub fn connect_timeout(mut self, timeout: Duration) -> Self {
100 self.connect_timeout = Some(timeout);
101 self
102 }
103
104 #[cfg(feature = "http-async-std")]
108 pub fn build<U: Into<String>>(self, url: U) -> Result<HttpClient, HttpClientError> {
109 Ok(HttpClient {
110 url: url.into(),
111 id: Arc::new(AtomicU64::new(1)),
112 client: surf::Client::new(),
113 headers: self.headers,
114 timeout: self.timeout,
115 })
116 }
117
118 #[cfg(feature = "http-tokio")]
120 pub fn build<U: Into<String>>(self, url: U) -> Result<HttpClient, HttpClientError> {
121 let builder = reqwest::Client::builder().default_headers(self.headers);
122 let builder = if let Some(timeout) = self.timeout {
123 builder.timeout(timeout)
124 } else {
125 builder
126 };
127 let builder = if let Some(timeout) = self.connect_timeout {
128 builder.connect_timeout(timeout)
129 } else {
130 builder
131 };
132 let client = builder.build()?;
133 Ok(HttpClient {
134 url: url.into(),
135 id: Arc::new(AtomicU64::new(1)),
136 client,
137 })
138 }
139}