use crate::connector::default_connector;
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep};
use aws_smithy_client::erase::DynConnector;
use aws_smithy_client::timeout;
use aws_types::os_shim_internal::{Env, Fs, TimeSource};
use aws_types::region::Region;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
#[cfg(feature = "tcp-connector")]
use aws_smithy_client::erase::boxclone::BoxCloneService;
#[derive(Clone)]
pub struct ProviderConfig {
env: Env,
fs: Fs,
time_source: TimeSource,
connector: HttpConnector,
sleep: Option<Arc<dyn AsyncSleep>>,
region: Option<Region>,
}
pub(crate) type MakeConnectorFn =
dyn Fn(&HttpSettings, Option<Arc<dyn AsyncSleep>>) -> Option<DynConnector> + Send + Sync;
#[derive(Clone)]
pub(crate) enum HttpConnector {
Prebuilt(Option<DynConnector>),
ConnectorFn(Arc<MakeConnectorFn>),
#[cfg(feature = "tcp-connector")]
TcpConnector(BoxCloneService<http::Uri, tokio::net::TcpStream, tower::BoxError>),
}
impl Default for HttpConnector {
fn default() -> Self {
Self::ConnectorFn(Arc::new(
|settings: &HttpSettings, sleep: Option<Arc<dyn AsyncSleep>>| {
default_connector(settings, sleep)
},
))
}
}
impl HttpConnector {
fn make_connector(
&self,
settings: &HttpSettings,
sleep: Option<Arc<dyn AsyncSleep>>,
) -> Option<DynConnector> {
match self {
HttpConnector::Prebuilt(conn) => conn.clone(),
HttpConnector::ConnectorFn(func) => func(settings, sleep),
#[cfg(feature = "tcp-connector")]
HttpConnector::TcpConnector(connection) => Some(DynConnector::new(
aws_smithy_client::hyper_ext::Adapter::builder()
.timeout(&settings.timeout_settings)
.sleep_impl(sleep.unwrap())
.build(connection.clone()),
)),
}
}
}
impl Debug for ProviderConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProviderConfig")
.field("env", &self.env)
.field("fs", &self.fs)
.field("sleep", &self.sleep)
.field("region", &self.region)
.finish()
}
}
impl Default for ProviderConfig {
fn default() -> Self {
Self {
env: Env::default(),
fs: Fs::default(),
time_source: TimeSource::default(),
connector: HttpConnector::default(),
sleep: default_async_sleep(),
region: None,
}
}
}
#[cfg(test)]
impl ProviderConfig {
pub fn no_configuration() -> Self {
use aws_types::os_shim_internal::ManualTimeSource;
use std::collections::HashMap;
use std::time::UNIX_EPOCH;
Self {
env: Env::from_slice(&[]),
fs: Fs::from_raw_map(HashMap::new()),
time_source: TimeSource::manual(&ManualTimeSource::new(UNIX_EPOCH)),
connector: HttpConnector::Prebuilt(None),
sleep: None,
region: None,
}
}
}
#[non_exhaustive]
#[derive(Default)]
pub(crate) struct HttpSettings {
#[allow(dead_code)] pub(crate) timeout_settings: timeout::Settings,
}
impl ProviderConfig {
pub fn without_region() -> Self {
Self::default()
}
pub fn empty() -> Self {
ProviderConfig {
env: Env::default(),
fs: Fs::default(),
time_source: TimeSource::default(),
connector: HttpConnector::Prebuilt(None),
sleep: None,
region: None,
}
}
#[cfg(feature = "default-provider")]
pub async fn with_default_region() -> Self {
Self::without_region().load_default_region().await
}
#[allow(dead_code)]
pub(crate) fn env(&self) -> Env {
self.env.clone()
}
#[allow(dead_code)]
pub(crate) fn fs(&self) -> Fs {
self.fs.clone()
}
#[allow(dead_code)]
pub(crate) fn time_source(&self) -> TimeSource {
self.time_source.clone()
}
#[allow(dead_code)]
pub(crate) fn default_connector(&self) -> Option<DynConnector> {
self.connector
.make_connector(&HttpSettings::default(), self.sleep.clone())
}
#[allow(dead_code)]
pub(crate) fn connector(&self, settings: &HttpSettings) -> Option<DynConnector> {
self.connector.make_connector(settings, self.sleep.clone())
}
#[allow(dead_code)]
pub(crate) fn sleep(&self) -> Option<Arc<dyn AsyncSleep>> {
self.sleep.clone()
}
#[allow(dead_code)]
pub(crate) fn region(&self) -> Option<Region> {
self.region.clone()
}
pub fn with_region(mut self, region: Option<Region>) -> Self {
self.region = region;
self
}
#[cfg(feature = "default-provider")]
pub async fn load_default_region(self) -> Self {
use crate::default_provider::region::DefaultRegionChain;
let provider_chain = DefaultRegionChain::builder().configure(&self).build();
self.with_region(provider_chain.region().await)
}
#[doc(hidden)]
pub fn with_fs(self, fs: Fs) -> Self {
ProviderConfig { fs, ..self }
}
#[doc(hidden)]
pub fn with_env(self, env: Env) -> Self {
ProviderConfig { env, ..self }
}
#[doc(hidden)]
pub fn with_time_source(self, time_source: TimeSource) -> Self {
ProviderConfig {
time_source,
..self
}
}
pub fn with_http_connector(self, connector: DynConnector) -> Self {
ProviderConfig {
connector: HttpConnector::Prebuilt(Some(connector)),
..self
}
}
#[cfg(feature = "tcp-connector")]
pub fn with_tcp_connector(
self,
connector: BoxCloneService<http::Uri, tokio::net::TcpStream, tower::BoxError>,
) -> Self {
ProviderConfig {
connector: HttpConnector::TcpConnector(connector),
..self
}
}
pub fn with_sleep(self, sleep: impl AsyncSleep + 'static) -> Self {
ProviderConfig {
sleep: Some(Arc::new(sleep)),
..self
}
}
}