mangayomi-mirror/rust/src/api/rhttp/client.rs
kodjomoustapha aa2b408144 +
- adding modify codes from the rhttp package
2024-09-11 12:04:01 +01:00

165 lines
5.1 KiB
Rust

use crate::api::rhttp::error::RhttpError;
use chrono::Duration;
use reqwest::{tls, Certificate};
pub use tokio_util::sync::CancellationToken;
pub struct ClientSettings {
pub timeout: Option<Duration>,
pub connect_timeout: Option<Duration>,
pub throw_on_status_code: bool,
pub proxy_settings: Option<ProxySettings>,
pub redirect_settings: Option<RedirectSettings>,
pub tls_settings: Option<TlsSettings>,
}
pub enum ProxySettings {
NoProxy,
}
pub enum RedirectSettings {
NoRedirect,
LimitedRedirects(i32),
}
pub struct TlsSettings {
pub trust_root_certificates: bool,
pub trusted_root_certificates: Vec<Vec<u8>>,
pub verify_certificates: bool,
pub client_certificate: Option<ClientCertificate>,
pub min_tls_version: Option<TlsVersion>,
pub max_tls_version: Option<TlsVersion>,
}
pub struct ClientCertificate {
pub certificate: Vec<u8>,
pub private_key: Vec<u8>,
}
pub enum TlsVersion {
Tls1_2,
Tls1_3,
}
impl Default for ClientSettings {
fn default() -> Self {
ClientSettings {
timeout: None,
connect_timeout: None,
throw_on_status_code: true,
proxy_settings: None,
redirect_settings: None,
tls_settings: None,
}
}
}
#[derive(Clone)]
pub struct RequestClient {
pub(crate) client: reqwest::Client,
pub(crate) throw_on_status_code: bool,
/// A token that can be used to cancel all requests made by this client.
pub(crate) cancel_token: CancellationToken,
}
impl RequestClient {
pub(crate) fn new_default() -> Self {
create_client(ClientSettings::default()).unwrap()
}
pub(crate) fn new(settings: ClientSettings) -> Result<RequestClient, RhttpError> {
create_client(settings)
}
}
fn create_client(settings: ClientSettings) -> Result<RequestClient, RhttpError> {
let client: reqwest::Client = {
let mut client = reqwest::Client::builder();
if let Some(proxy_settings) = settings.proxy_settings {
match proxy_settings {
ProxySettings::NoProxy => client = client.no_proxy(),
}
}
if let Some(redirect_settings) = settings.redirect_settings {
client = match redirect_settings {
RedirectSettings::NoRedirect => client.redirect(reqwest::redirect::Policy::none()),
RedirectSettings::LimitedRedirects(max_redirects) => {
client.redirect(reqwest::redirect::Policy::limited(max_redirects as usize))
}
};
}
if let Some(timeout) = settings.timeout {
client = client.timeout(
timeout
.to_std()
.map_err(|e| RhttpError::RhttpUnknownError(e.to_string()))?,
);
}
if let Some(timeout) = settings.connect_timeout {
client = client.connect_timeout(
timeout
.to_std()
.map_err(|e| RhttpError::RhttpUnknownError(e.to_string()))?,
);
}
if let Some(tls_settings) = settings.tls_settings {
if !tls_settings.trust_root_certificates {
client = client.tls_built_in_root_certs(false);
}
for cert in tls_settings.trusted_root_certificates {
client =
client.add_root_certificate(Certificate::from_pem(&cert).map_err(|e| {
RhttpError::RhttpUnknownError(format!(
"Error adding trusted certificate: {e:?}"
))
})?);
}
if !tls_settings.verify_certificates {
client = client.danger_accept_invalid_certs(true);
}
if let Some(client_certificate) = tls_settings.client_certificate {
let identity = &[
client_certificate.certificate.as_slice(),
"\n".as_bytes(),
client_certificate.private_key.as_slice(),
]
.concat();
client = client.identity(
reqwest::Identity::from_pem(identity)
.map_err(|e| RhttpError::RhttpUnknownError(format!("{e:?}")))?,
);
}
if let Some(min_tls_version) = tls_settings.min_tls_version {
client = client.min_tls_version(match min_tls_version {
TlsVersion::Tls1_2 => tls::Version::TLS_1_2,
TlsVersion::Tls1_3 => tls::Version::TLS_1_3,
});
}
if let Some(max_tls_version) = tls_settings.max_tls_version {
client = client.max_tls_version(match max_tls_version {
TlsVersion::Tls1_2 => tls::Version::TLS_1_2,
TlsVersion::Tls1_3 => tls::Version::TLS_1_3,
});
}
}
client
.build()
.map_err(|e| RhttpError::RhttpUnknownError(format!("{e:?}")))?
};
Ok(RequestClient {
client,
throw_on_status_code: settings.throw_on_status_code,
cancel_token: CancellationToken::new(),
})
}