use std::collections::BTreeMap;
use std::fmt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::client::Client;
use crate::tls::{Certificate, Identity};
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Auth {
pub username: String,
pub password: Option<String>,
}
#[derive(Clone)]
pub struct ClientConfig {
url: Arc<dyn Fn() -> Url + Send + Sync + 'static>,
root_certs: Vec<Certificate>,
identity: Option<Identity>,
auth: Option<Auth>,
dns_overrides: BTreeMap<String, Vec<SocketAddr>>,
}
impl fmt::Debug for ClientConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ClientConfig")
.field("url", &"...")
.field("root_certs", &self.root_certs)
.field("identity", &self.identity)
.field("auth", &self.auth)
.field("dns_overrides", &self.dns_overrides)
.finish()
}
}
impl ClientConfig {
pub fn new(url: Url) -> ClientConfig {
ClientConfig {
url: Arc::new(move || url.clone()),
root_certs: Vec::new(),
identity: None,
auth: None,
dns_overrides: BTreeMap::new(),
}
}
pub fn add_root_certificate(mut self, cert: Certificate) -> ClientConfig {
self.root_certs.push(cert);
self
}
pub fn identity(mut self, identity: Identity) -> ClientConfig {
self.identity = Some(identity);
self
}
pub fn auth(mut self, username: String, password: Option<String>) -> ClientConfig {
self.auth = Some(Auth { username, password });
self
}
pub fn resolve_to_addrs(mut self, domain: &str, addrs: &[SocketAddr]) -> ClientConfig {
self.dns_overrides.insert(domain.into(), addrs.into());
self
}
pub fn dynamic_url<F: Fn() -> Url + Send + Sync + 'static>(
mut self,
callback: F,
) -> ClientConfig {
self.url = Arc::new(callback);
self
}
pub fn build(self) -> Result<Client, anyhow::Error> {
let mut builder = reqwest::ClientBuilder::new();
for root_cert in self.root_certs {
builder = builder.add_root_certificate(root_cert.into());
}
if let Some(ident) = self.identity {
builder = builder.identity(ident.into());
}
for (domain, addrs) in self.dns_overrides {
builder = builder.resolve_to_addrs(&domain, &addrs);
}
let timeout = Duration::from_secs(60);
let inner = builder
.redirect(reqwest::redirect::Policy::none())
.timeout(timeout)
.build()
.unwrap();
Client::new(inner, self.url, self.auth, timeout)
}
}