use crate::profile;
#[allow(deprecated)]
use crate::profile::profile_file::ProfileFiles;
use crate::profile::{ProfileFileLoadError, ProfileSet};
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
use aws_smithy_async::time::{SharedTimeSource, TimeSource};
use aws_smithy_runtime_api::client::http::HttpClient;
use aws_smithy_runtime_api::shared::IntoShared;
use aws_smithy_types::error::display::DisplayErrorContext;
use aws_smithy_types::retry::RetryConfig;
use aws_types::os_shim_internal::{Env, Fs};
use aws_types::region::Region;
use aws_types::sdk_config::SharedHttpClient;
use aws_types::SdkConfig;
use std::borrow::Cow;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use tokio::sync::OnceCell;
#[derive(Clone)]
pub struct ProviderConfig {
env: Env,
fs: Fs,
time_source: SharedTimeSource,
http_client: Option<SharedHttpClient>,
sleep_impl: Option<SharedAsyncSleep>,
region: Option<Region>,
use_fips: Option<bool>,
use_dual_stack: Option<bool>,
parsed_profile: Arc<OnceCell<Result<ProfileSet, ProfileFileLoadError>>>,
#[allow(deprecated)]
profile_files: ProfileFiles,
profile_name_override: Option<Cow<'static, str>>,
}
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("time_source", &self.time_source)
.field("http_client", &self.http_client)
.field("sleep_impl", &self.sleep_impl)
.field("region", &self.region)
.field("use_fips", &self.use_fips)
.field("use_dual_stack", &self.use_dual_stack)
.field("profile_name_override", &self.profile_name_override)
.finish()
}
}
impl Default for ProviderConfig {
fn default() -> Self {
Self {
env: Env::default(),
fs: Fs::default(),
time_source: SharedTimeSource::default(),
http_client: None,
sleep_impl: default_async_sleep(),
region: None,
use_fips: None,
use_dual_stack: None,
parsed_profile: Default::default(),
#[allow(deprecated)]
profile_files: ProfileFiles::default(),
profile_name_override: None,
}
}
}
#[cfg(test)]
impl ProviderConfig {
pub fn no_configuration() -> Self {
use aws_smithy_async::time::StaticTimeSource;
use std::collections::HashMap;
use std::time::UNIX_EPOCH;
let fs = Fs::from_raw_map(HashMap::new());
let env = Env::from_slice(&[]);
Self {
parsed_profile: Default::default(),
#[allow(deprecated)]
profile_files: ProfileFiles::default(),
env,
fs,
time_source: SharedTimeSource::new(StaticTimeSource::new(UNIX_EPOCH)),
http_client: None,
sleep_impl: None,
region: None,
use_fips: None,
use_dual_stack: None,
profile_name_override: None,
}
}
}
impl ProviderConfig {
pub fn without_region() -> Self {
Self::default()
}
pub fn empty() -> Self {
ProviderConfig {
env: Env::default(),
fs: Fs::default(),
time_source: SharedTimeSource::default(),
http_client: None,
sleep_impl: None,
region: None,
use_fips: None,
use_dual_stack: None,
parsed_profile: Default::default(),
#[allow(deprecated)]
profile_files: ProfileFiles::default(),
profile_name_override: None,
}
}
pub(crate) fn init(
time_source: SharedTimeSource,
sleep_impl: Option<SharedAsyncSleep>,
) -> Self {
Self {
parsed_profile: Default::default(),
#[allow(deprecated)]
profile_files: ProfileFiles::default(),
env: Env::default(),
fs: Fs::default(),
time_source,
http_client: None,
sleep_impl,
region: None,
use_fips: None,
use_dual_stack: None,
profile_name_override: None,
}
}
pub async fn with_default_region() -> Self {
Self::without_region().load_default_region().await
}
pub(crate) fn client_config(&self) -> SdkConfig {
let mut builder = SdkConfig::builder()
.retry_config(RetryConfig::standard())
.region(self.region())
.time_source(self.time_source())
.use_fips(self.use_fips().unwrap_or_default())
.use_dual_stack(self.use_dual_stack().unwrap_or_default())
.behavior_version(crate::BehaviorVersion::latest());
builder.set_http_client(self.http_client.clone());
builder.set_sleep_impl(self.sleep_impl.clone());
builder.build()
}
#[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) -> SharedTimeSource {
self.time_source.clone()
}
#[allow(dead_code)]
pub(crate) fn http_client(&self) -> Option<SharedHttpClient> {
self.http_client.clone()
}
#[allow(dead_code)]
pub(crate) fn sleep_impl(&self) -> Option<SharedAsyncSleep> {
self.sleep_impl.clone()
}
#[allow(dead_code)]
pub(crate) fn region(&self) -> Option<Region> {
self.region.clone()
}
#[allow(dead_code)]
pub(crate) fn use_fips(&self) -> Option<bool> {
self.use_fips
}
#[allow(dead_code)]
pub(crate) fn use_dual_stack(&self) -> Option<bool> {
self.use_dual_stack
}
pub(crate) async fn try_profile(&self) -> Result<&ProfileSet, &ProfileFileLoadError> {
let parsed_profile = self
.parsed_profile
.get_or_init(|| async {
let profile = profile::load(
&self.fs,
&self.env,
&self.profile_files,
self.profile_name_override.clone(),
)
.await;
if let Err(err) = profile.as_ref() {
tracing::warn!(err = %DisplayErrorContext(&err), "failed to parse profile")
}
profile
})
.await;
parsed_profile.as_ref()
}
pub(crate) async fn profile(&self) -> Option<&ProfileSet> {
self.try_profile().await.ok()
}
pub fn with_region(mut self, region: Option<Region>) -> Self {
self.region = region;
self
}
pub(crate) fn with_use_fips(mut self, use_fips: Option<bool>) -> Self {
self.use_fips = use_fips;
self
}
pub(crate) fn with_use_dual_stack(mut self, use_dual_stack: Option<bool>) -> Self {
self.use_dual_stack = use_dual_stack;
self
}
pub(crate) fn with_profile_name(self, profile_name: String) -> Self {
let profile_files = self.profile_files.clone();
self.with_profile_config(Some(profile_files), Some(profile_name))
}
#[allow(deprecated)]
pub(crate) fn with_profile_config(
self,
profile_files: Option<ProfileFiles>,
profile_name_override: Option<String>,
) -> Self {
if profile_files.is_none() && profile_name_override.is_none() {
return self;
}
ProviderConfig {
parsed_profile: Default::default(),
profile_files: profile_files.unwrap_or(self.profile_files),
profile_name_override: profile_name_override
.map(Cow::Owned)
.or(self.profile_name_override),
..self
}
}
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)
}
pub(crate) fn with_fs(self, fs: Fs) -> Self {
ProviderConfig {
parsed_profile: Default::default(),
fs,
..self
}
}
pub(crate) fn with_env(self, env: Env) -> Self {
ProviderConfig {
parsed_profile: Default::default(),
env,
..self
}
}
pub fn with_time_source(self, time_source: impl TimeSource + 'static) -> Self {
ProviderConfig {
time_source: time_source.into_shared(),
..self
}
}
pub fn with_http_client(self, http_client: impl HttpClient + 'static) -> Self {
ProviderConfig {
http_client: Some(http_client.into_shared()),
..self
}
}
pub fn with_sleep_impl(self, sleep_impl: impl AsyncSleep + 'static) -> Self {
ProviderConfig {
sleep_impl: Some(sleep_impl.into_shared()),
..self
}
}
}