use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use reqwest::cookie::Jar;
#[derive(Debug, Clone)]
pub enum TlsMode {
System,
CustomCa(PathBuf),
DangerAcceptInvalid,
}
#[derive(Debug, Clone)]
pub struct TransportConfig {
pub tls: TlsMode,
pub timeout: Duration,
pub cookie_jar: Option<Arc<Jar>>,
}
impl Default for TransportConfig {
fn default() -> Self {
Self {
tls: TlsMode::DangerAcceptInvalid,
timeout: Duration::from_secs(30),
cookie_jar: None,
}
}
}
impl TransportConfig {
pub fn build_client(&self) -> Result<reqwest::Client, crate::error::Error> {
let mut builder = reqwest::Client::builder()
.timeout(self.timeout)
.user_agent("unifly/0.1.0");
match &self.tls {
TlsMode::System => {}
TlsMode::CustomCa(path) => {
let cert_pem = std::fs::read(path).map_err(|e| {
crate::error::Error::Tls(format!("failed to read CA cert: {e}"))
})?;
let cert = reqwest::Certificate::from_pem(&cert_pem)
.map_err(|e| crate::error::Error::Tls(format!("invalid CA cert: {e}")))?;
builder = builder.add_root_certificate(cert);
}
TlsMode::DangerAcceptInvalid => {
builder = builder.danger_accept_invalid_certs(true);
}
}
if let Some(ref jar) = self.cookie_jar {
builder = builder.cookie_provider(Arc::clone(jar));
}
builder
.build()
.map_err(|e| crate::error::Error::Tls(format!("failed to build HTTP client: {e}")))
}
pub fn build_client_with_headers(
&self,
headers: reqwest::header::HeaderMap,
) -> Result<reqwest::Client, crate::error::Error> {
let mut builder = reqwest::Client::builder()
.timeout(self.timeout)
.user_agent("unifly/0.1.0")
.default_headers(headers);
match &self.tls {
TlsMode::System => {}
TlsMode::CustomCa(path) => {
let cert_pem = std::fs::read(path).map_err(|e| {
crate::error::Error::Tls(format!("failed to read CA cert: {e}"))
})?;
let cert = reqwest::Certificate::from_pem(&cert_pem)
.map_err(|e| crate::error::Error::Tls(format!("invalid CA cert: {e}")))?;
builder = builder.add_root_certificate(cert);
}
TlsMode::DangerAcceptInvalid => {
builder = builder.danger_accept_invalid_certs(true);
}
}
if let Some(ref jar) = self.cookie_jar {
builder = builder.cookie_provider(Arc::clone(jar));
}
builder
.build()
.map_err(|e| crate::error::Error::Tls(format!("failed to build HTTP client: {e}")))
}
pub fn with_cookie_jar(mut self) -> Self {
self.cookie_jar = Some(Arc::new(Jar::default()));
self
}
}