use crate::box_error::BoxError;
use crate::client::runtime_components::sealed::ValidateConfig;
use crate::impl_shared_conversions;
use aws_smithy_types::config_bag::{Storable, StoreReplace};
use aws_smithy_types::endpoint::Endpoint;
use aws_smithy_types::type_erasure::TypeErasedBox;
use error::InvalidEndpointError;
use http::uri::Authority;
use std::fmt;
use std::str::FromStr;
use std::sync::Arc;
new_type_future! {
#[doc = "Future for [`EndpointResolver::resolve_endpoint`]."]
pub struct EndpointFuture<'a, Endpoint, BoxError>;
}
#[derive(Debug)]
pub struct EndpointResolverParams(TypeErasedBox);
impl EndpointResolverParams {
pub fn new<T: fmt::Debug + Send + Sync + 'static>(params: T) -> Self {
Self(TypeErasedBox::new(params))
}
pub fn get<T: fmt::Debug + Send + Sync + 'static>(&self) -> Option<&T> {
self.0.downcast_ref()
}
}
impl Storable for EndpointResolverParams {
type Storer = StoreReplace<Self>;
}
pub trait ResolveEndpoint: Send + Sync + fmt::Debug {
fn resolve_endpoint<'a>(&'a self, params: &'a EndpointResolverParams) -> EndpointFuture<'a>;
}
#[derive(Clone, Debug)]
pub struct SharedEndpointResolver(Arc<dyn ResolveEndpoint>);
impl SharedEndpointResolver {
pub fn new(endpoint_resolver: impl ResolveEndpoint + 'static) -> Self {
Self(Arc::new(endpoint_resolver))
}
}
impl ResolveEndpoint for SharedEndpointResolver {
fn resolve_endpoint<'a>(&'a self, params: &'a EndpointResolverParams) -> EndpointFuture<'a> {
self.0.resolve_endpoint(params)
}
}
impl ValidateConfig for SharedEndpointResolver {}
impl_shared_conversions!(convert SharedEndpointResolver from ResolveEndpoint using SharedEndpointResolver::new);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EndpointPrefix(String);
impl EndpointPrefix {
pub fn new(prefix: impl Into<String>) -> Result<Self, InvalidEndpointError> {
let prefix = prefix.into();
match Authority::from_str(&prefix) {
Ok(_) => Ok(EndpointPrefix(prefix)),
Err(err) => Err(InvalidEndpointError::failed_to_construct_authority(
prefix, err,
)),
}
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Storable for EndpointPrefix {
type Storer = StoreReplace<Self>;
}
pub mod error {
use crate::box_error::BoxError;
use std::error::Error as StdError;
use std::fmt;
#[derive(Debug)]
pub struct ResolveEndpointError {
message: String,
source: Option<BoxError>,
}
impl ResolveEndpointError {
pub fn message(message: impl Into<String>) -> Self {
Self {
message: message.into(),
source: None,
}
}
pub fn with_source(self, source: Option<BoxError>) -> Self {
Self { source, ..self }
}
pub fn from_source(message: impl Into<String>, source: impl Into<BoxError>) -> Self {
Self::message(message).with_source(Some(source.into()))
}
}
impl fmt::Display for ResolveEndpointError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl StdError for ResolveEndpointError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.source.as_ref().map(|err| err.as_ref() as _)
}
}
#[derive(Debug)]
pub(super) enum InvalidEndpointErrorKind {
EndpointMustHaveScheme,
FailedToConstructAuthority { authority: String, source: BoxError },
FailedToConstructUri { source: BoxError },
}
#[derive(Debug)]
pub struct InvalidEndpointError {
pub(super) kind: InvalidEndpointErrorKind,
}
impl InvalidEndpointError {
pub fn endpoint_must_have_scheme() -> Self {
Self {
kind: InvalidEndpointErrorKind::EndpointMustHaveScheme,
}
}
pub fn failed_to_construct_authority(
authority: impl Into<String>,
source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> Self {
Self {
kind: InvalidEndpointErrorKind::FailedToConstructAuthority {
authority: authority.into(),
source: source.into(),
},
}
}
pub fn failed_to_construct_uri(
source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> Self {
Self {
kind: InvalidEndpointErrorKind::FailedToConstructUri {
source: source.into(),
},
}
}
}
impl From<InvalidEndpointErrorKind> for InvalidEndpointError {
fn from(kind: InvalidEndpointErrorKind) -> Self {
Self { kind }
}
}
impl fmt::Display for InvalidEndpointError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InvalidEndpointErrorKind as ErrorKind;
match &self.kind {
ErrorKind::EndpointMustHaveScheme => write!(f, "endpoint must contain a valid scheme"),
ErrorKind::FailedToConstructAuthority { authority, source: _ } => write!(
f,
"endpoint must contain a valid authority when combined with endpoint prefix: {authority}"
),
ErrorKind::FailedToConstructUri { .. } => write!(f, "failed to construct URI"),
}
}
}
impl StdError for InvalidEndpointError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
use InvalidEndpointErrorKind as ErrorKind;
match &self.kind {
ErrorKind::FailedToConstructUri { source } => Some(source.as_ref()),
ErrorKind::FailedToConstructAuthority {
authority: _,
source,
} => Some(source.as_ref()),
ErrorKind::EndpointMustHaveScheme => None,
}
}
}
}