use std::time::Duration;
use reqwest::{
self,
blocking::{
Client as ReqwestClient, ClientBuilder as ReqwestClientBuilder, Request as ReqwestRequest,
RequestBuilder as ReqwestRequestBuilder, Response as ReqwestResponse,
},
IntoUrl,
};
#[cfg(feature = "send3")]
use websocket::{
self, client::sync::Client as WsClient, result::WebSocketResult as WsResult,
stream::sync::NetworkStream as WsNetworkStream,
};
#[cfg(feature = "send3")]
const WEBSOCKET_PROTOCOL: &str = "ffsend";
pub struct Client {
config: ClientConfig,
reqwest: ReqwestClient,
}
impl Client {
pub fn new(config: ClientConfig, transfer: bool) -> Self {
let mut builder = ReqwestClientBuilder::new();
match config.timeout {
Some(timeout) if !transfer => builder = builder.timeout(timeout),
_ => {}
}
match config.transfer_timeout {
Some(timeout) if transfer => builder = builder.timeout(timeout),
_ => {}
}
let reqwest = builder.build().expect("failed to build reqwest client");
Self { config, reqwest }
}
pub fn get<U: IntoUrl>(&self, url: U) -> ReqwestRequestBuilder {
self.configure(self.reqwest.get(url))
}
pub fn post<U: IntoUrl>(&self, url: U) -> ReqwestRequestBuilder {
self.configure(self.reqwest.post(url))
}
pub fn execute(&self, request: ReqwestRequest) -> reqwest::Result<ReqwestResponse> {
self.reqwest.execute(request)
}
#[cfg(feature = "send3")]
pub fn websocket(&self, url: &str) -> WsResult<WsClient<Box<dyn WsNetworkStream + Send>>> {
let mut builder = websocket::ClientBuilder::new(url)
.expect("failed to set up websocket builder")
.add_protocol(WEBSOCKET_PROTOCOL);
if let Some((user, password)) = &self.config.basic_auth {
let mut headers = websocket::header::Headers::new();
headers.set(websocket::header::Authorization(websocket::header::Basic {
username: user.to_owned(),
password: password.to_owned(),
}));
builder = builder.custom_headers(&headers);
}
builder.connect(None)
}
fn configure(&self, mut client: ReqwestRequestBuilder) -> ReqwestRequestBuilder {
if let Some((user, password)) = &self.config.basic_auth {
client = client.basic_auth(user, password.to_owned());
}
client
}
}
#[derive(Clone, Debug, Builder)]
pub struct ClientConfig {
#[builder(default = "Some(Duration::from_secs(30))")]
timeout: Option<Duration>,
#[builder(default = "Some(Duration::from_secs(86400))")]
transfer_timeout: Option<Duration>,
#[builder(default)]
basic_auth: Option<(String, Option<String>)>,
}
impl ClientConfig {
pub fn client(self, transfer: bool) -> Client {
Client::new(self, transfer)
}
}
impl Default for ClientConfig {
fn default() -> Self {
Self {
timeout: None,
transfer_timeout: None,
basic_auth: None,
}
}
}