pub mod backoff;
#[allow(unused)]
pub mod pagination;
pub mod retry;
pub mod token;
use crate::UnityCatalogError;
use crate::client::retry::RetryConfig;
use deltalake_core::data_catalog::DataCatalogResult;
use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::{ClientBuilder, Proxy};
use reqwest_middleware::ClientWithMiddleware;
use reqwest_retry::{RetryTransientMiddleware, policies::ExponentialBackoff};
use std::time::Duration;
use typed_builder::TypedBuilder;
fn map_client_error(e: reqwest::Error) -> super::DataCatalogError {
super::DataCatalogError::Generic {
catalog: "HTTP client",
source: Box::new(e),
}
}
static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
#[derive(Debug, Clone, Default, TypedBuilder)]
#[builder(doc)]
pub struct ClientOptions {
#[builder(default, setter(strip_option))]
user_agent: Option<HeaderValue>,
#[builder(default, setter(strip_option))]
default_headers: Option<HeaderMap>,
#[builder(default, setter(strip_option, into))]
proxy_url: Option<String>,
#[builder(default)]
pub(crate) allow_http: bool,
#[builder(default)]
allow_insecure: bool,
#[builder(default, setter(strip_option))]
timeout: Option<Duration>,
#[builder(default, setter(strip_option))]
connect_timeout: Option<Duration>,
#[builder(default, setter(strip_option))]
pool_idle_timeout: Option<Duration>,
#[builder(default, setter(strip_option))]
pool_max_idle_per_host: Option<usize>,
#[builder(default, setter(strip_option))]
http2_keep_alive_interval: Option<Duration>,
#[builder(default, setter(strip_option))]
http2_keep_alive_timeout: Option<Duration>,
#[builder(default)]
http2_keep_alive_while_idle: bool,
#[builder(default)]
http1_only: bool,
#[builder(default)]
http2_only: bool,
#[builder(default, setter(strip_option))]
retry_config: Option<RetryConfig>,
}
impl ClientOptions {
pub(crate) fn client(&self) -> DataCatalogResult<ClientWithMiddleware> {
let mut builder = ClientBuilder::new();
match &self.user_agent {
Some(user_agent) => builder = builder.user_agent(user_agent),
None => builder = builder.user_agent(DEFAULT_USER_AGENT),
}
if let Some(headers) = &self.default_headers {
builder = builder.default_headers(headers.clone())
}
if let Some(proxy) = &self.proxy_url {
let proxy = Proxy::all(proxy).map_err(map_client_error)?;
builder = builder.proxy(proxy);
}
if let Some(timeout) = self.timeout {
builder = builder.timeout(timeout)
}
if let Some(timeout) = self.connect_timeout {
builder = builder.connect_timeout(timeout)
}
if let Some(timeout) = self.pool_idle_timeout {
builder = builder.pool_idle_timeout(timeout)
}
if let Some(max) = self.pool_max_idle_per_host {
builder = builder.pool_max_idle_per_host(max)
}
if let Some(interval) = self.http2_keep_alive_interval {
builder = builder.http2_keep_alive_interval(interval)
}
if let Some(interval) = self.http2_keep_alive_timeout {
builder = builder.http2_keep_alive_timeout(interval)
}
if self.http2_keep_alive_while_idle {
builder = builder.http2_keep_alive_while_idle(true)
}
if self.http1_only {
builder = builder.http1_only()
}
if self.http2_only {
builder = builder.http2_prior_knowledge()
}
if self.allow_insecure {
builder = builder.danger_accept_invalid_certs(self.allow_insecure)
}
let inner_client = builder
.https_only(!self.allow_http)
.build()
.map_err(UnityCatalogError::from)?;
let retry_policy = self
.retry_config
.as_ref()
.map(|retry| retry.into())
.unwrap_or(ExponentialBackoff::builder().build_with_max_retries(3));
let middleware = RetryTransientMiddleware::new_with_policy(retry_policy);
Ok(reqwest_middleware::ClientBuilder::new(inner_client)
.with(middleware)
.build())
}
}