use std::sync::Arc;
use std::time::Duration;
use snafu::ResultExt as _;
use url::Url;
use crate::NifiClient;
use crate::NifiError;
use crate::credentials::CredentialProvider;
use crate::error::{HttpSnafu, InvalidBaseUrlSnafu, InvalidCertificateSnafu};
pub struct NifiClientBuilder {
base_url: Url,
timeout: Option<Duration>,
connect_timeout: Option<Duration>,
proxy_all: Option<Url>,
proxy_http: Option<Url>,
proxy_https: Option<Url>,
danger_accept_invalid_certs: bool,
root_certificates: Vec<Vec<u8>>,
credential_provider: Option<Arc<dyn CredentialProvider>>,
retry_policy: Option<crate::retry::RetryPolicy>,
#[cfg(feature = "dynamic")]
version_strategy: Option<crate::dynamic::VersionResolutionStrategy>,
}
impl std::fmt::Debug for NifiClientBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = f.debug_struct("NifiClientBuilder");
s.field("base_url", &self.base_url)
.field("timeout", &self.timeout)
.field("connect_timeout", &self.connect_timeout)
.field("proxy_all", &self.proxy_all)
.field("proxy_http", &self.proxy_http)
.field("proxy_https", &self.proxy_https)
.field(
"danger_accept_invalid_certs",
&self.danger_accept_invalid_certs,
)
.field(
"root_certificates",
&format!("[{} certs]", self.root_certificates.len()),
)
.field(
"credential_provider",
&self.credential_provider.as_ref().map(|c| format!("{c:?}")),
)
.field("retry_policy", &self.retry_policy);
#[cfg(feature = "dynamic")]
s.field("version_strategy", &self.version_strategy);
s.finish()
}
}
impl NifiClientBuilder {
pub fn new(base_url: &str) -> Result<Self, NifiError> {
let base_url = Url::parse(base_url).context(InvalidBaseUrlSnafu)?;
Ok(Self {
base_url,
timeout: None,
connect_timeout: None,
proxy_all: None,
proxy_http: None,
proxy_https: None,
danger_accept_invalid_certs: false,
root_certificates: Vec::new(),
credential_provider: None,
retry_policy: None,
#[cfg(feature = "dynamic")]
version_strategy: None,
})
}
pub fn timeout(mut self, duration: Duration) -> Self {
self.timeout = Some(duration);
self
}
pub fn connect_timeout(mut self, duration: Duration) -> Self {
self.connect_timeout = Some(duration);
self
}
pub fn proxy(mut self, url: Url) -> Self {
self.proxy_all = Some(url);
self
}
pub fn http_proxy(mut self, url: Url) -> Self {
self.proxy_http = Some(url);
self
}
pub fn https_proxy(mut self, url: Url) -> Self {
self.proxy_https = Some(url);
self
}
pub fn danger_accept_invalid_certs(mut self, accept: bool) -> Self {
self.danger_accept_invalid_certs = accept;
self
}
pub fn add_root_certificate(mut self, pem: &[u8]) -> Self {
self.root_certificates.push(pem.to_vec());
self
}
pub fn credential_provider(mut self, provider: impl CredentialProvider + 'static) -> Self {
self.credential_provider = Some(Arc::new(provider));
self
}
pub fn retry_policy(mut self, policy: crate::retry::RetryPolicy) -> Self {
self.retry_policy = Some(policy);
self
}
#[cfg(feature = "dynamic")]
pub fn version_strategy(mut self, strategy: crate::dynamic::VersionResolutionStrategy) -> Self {
self.version_strategy = Some(strategy);
self
}
pub fn build(self) -> Result<NifiClient, NifiError> {
let mut builder = reqwest::Client::builder()
.danger_accept_invalid_certs(self.danger_accept_invalid_certs);
if let Some(d) = self.timeout {
builder = builder.timeout(d);
}
if let Some(d) = self.connect_timeout {
builder = builder.connect_timeout(d);
}
for pem in &self.root_certificates {
let cert = reqwest::Certificate::from_pem(pem).context(InvalidCertificateSnafu)?;
builder = builder.add_root_certificate(cert);
}
if let Some(url) = self.proxy_all {
let proxy = reqwest::Proxy::all(url.as_str()).context(HttpSnafu)?;
builder = builder.proxy(proxy);
}
if let Some(url) = self.proxy_http {
let proxy = reqwest::Proxy::http(url.as_str()).context(HttpSnafu)?;
builder = builder.proxy(proxy);
}
if let Some(url) = self.proxy_https {
let proxy = reqwest::Proxy::https(url.as_str()).context(HttpSnafu)?;
builder = builder.proxy(proxy);
}
let http = builder.build().context(HttpSnafu)?;
Ok(NifiClient::from_parts(
self.base_url,
http,
self.credential_provider,
self.retry_policy,
))
}
#[cfg(feature = "dynamic")]
pub fn build_dynamic(self) -> Result<crate::dynamic::DynamicClient, NifiError> {
let strategy = self.version_strategy.unwrap_or_default();
let client = self.build()?;
Ok(crate::dynamic::DynamicClient::with_strategy(
client, strategy,
))
}
}