1use std::time::Duration;
2
3use reqwest::{
4 self,
5 blocking::{
6 Client as ReqwestClient, ClientBuilder as ReqwestClientBuilder, Request as ReqwestRequest,
7 RequestBuilder as ReqwestRequestBuilder, Response as ReqwestResponse,
8 },
9 IntoUrl,
10};
11#[cfg(feature = "send3")]
12use websocket::{
13 self, client::sync::Client as WsClient, result::WebSocketResult as WsResult,
14 stream::sync::NetworkStream as WsNetworkStream,
15};
16
17#[cfg(feature = "send3")]
19const WEBSOCKET_PROTOCOL: &str = "ffsend";
20
21pub struct Client {
23 config: ClientConfig,
25
26 reqwest: ReqwestClient,
28}
29
30impl Client {
31 pub fn new(config: ClientConfig, transfer: bool) -> Self {
36 let mut builder = ReqwestClientBuilder::new();
38 match config.timeout {
39 Some(timeout) if !transfer => builder = builder.timeout(timeout),
40 _ => {}
41 }
42 match config.transfer_timeout {
43 Some(timeout) if transfer => builder = builder.timeout(timeout),
44 _ => {}
45 }
46 let reqwest = builder.build().expect("failed to build reqwest client");
47
48 Self { config, reqwest }
50 }
51
52 pub fn get<U: IntoUrl>(&self, url: U) -> ReqwestRequestBuilder {
54 self.configure(self.reqwest.get(url))
55 }
56
57 pub fn post<U: IntoUrl>(&self, url: U) -> ReqwestRequestBuilder {
59 self.configure(self.reqwest.post(url))
60 }
61
62 pub fn execute(&self, request: ReqwestRequest) -> reqwest::Result<ReqwestResponse> {
65 self.reqwest.execute(request)
66 }
67
68 #[cfg(feature = "send3")]
70 pub fn websocket(&self, url: &str) -> WsResult<WsClient<Box<dyn WsNetworkStream + Send>>> {
71 let mut builder = websocket::ClientBuilder::new(url)
73 .expect("failed to set up websocket builder")
74 .add_protocol(WEBSOCKET_PROTOCOL);
75
76 if let Some((user, password)) = &self.config.basic_auth {
78 let mut headers = websocket::header::Headers::new();
79 headers.set(websocket::header::Authorization(websocket::header::Basic {
80 username: user.to_owned(),
81 password: password.to_owned(),
82 }));
83 builder = builder.custom_headers(&headers);
84 }
85
86 builder.connect(None)
88 }
89
90 fn configure(&self, mut client: ReqwestRequestBuilder) -> ReqwestRequestBuilder {
92 if let Some((user, password)) = &self.config.basic_auth {
94 client = client.basic_auth(user, password.to_owned());
95 }
96
97 client
98 }
99}
100
101#[derive(Clone, Debug, Builder)]
103pub struct ClientConfig {
104 #[builder(default = "Some(Duration::from_secs(30))")]
106 timeout: Option<Duration>,
107
108 #[builder(default = "Some(Duration::from_secs(86400))")]
110 transfer_timeout: Option<Duration>,
111
112 #[builder(default)]
116 basic_auth: Option<(String, Option<String>)>,
117 }
119
120impl ClientConfig {
121 pub fn client(self, transfer: bool) -> Client {
125 Client::new(self, transfer)
126 }
127}
128
129impl Default for ClientConfig {
130 fn default() -> Self {
131 Self {
132 timeout: None,
133 transfer_timeout: None,
134 basic_auth: None,
135 }
136 }
137}