aws_smithy_runtime_api/client/
endpoint.rs
1use crate::box_error::BoxError;
9use crate::client::runtime_components::sealed::ValidateConfig;
10use crate::impl_shared_conversions;
11use aws_smithy_types::config_bag::{Storable, StoreReplace};
12use aws_smithy_types::endpoint::Endpoint;
13use aws_smithy_types::type_erasure::TypeErasedBox;
14use error::InvalidEndpointError;
15use http_02x::uri::Authority;
16use std::fmt;
17use std::str::FromStr;
18use std::sync::Arc;
19
20new_type_future! {
21 #[doc = "Future for [`EndpointResolver::resolve_endpoint`]."]
22 pub struct EndpointFuture<'a, Endpoint, BoxError>;
23}
24
25#[derive(Debug)]
31pub struct EndpointResolverParams(TypeErasedBox);
32
33impl EndpointResolverParams {
34 pub fn new<T: fmt::Debug + Send + Sync + 'static>(params: T) -> Self {
36 Self(TypeErasedBox::new(params))
37 }
38
39 pub fn get<T: fmt::Debug + Send + Sync + 'static>(&self) -> Option<&T> {
41 self.0.downcast_ref()
42 }
43}
44
45impl Storable for EndpointResolverParams {
46 type Storer = StoreReplace<Self>;
47}
48
49pub trait ResolveEndpoint: Send + Sync + fmt::Debug {
51 fn resolve_endpoint<'a>(&'a self, params: &'a EndpointResolverParams) -> EndpointFuture<'a>;
53}
54
55#[derive(Clone, Debug)]
59pub struct SharedEndpointResolver(Arc<dyn ResolveEndpoint>);
60
61impl SharedEndpointResolver {
62 pub fn new(endpoint_resolver: impl ResolveEndpoint + 'static) -> Self {
64 Self(Arc::new(endpoint_resolver))
65 }
66}
67
68impl ResolveEndpoint for SharedEndpointResolver {
69 fn resolve_endpoint<'a>(&'a self, params: &'a EndpointResolverParams) -> EndpointFuture<'a> {
70 self.0.resolve_endpoint(params)
71 }
72}
73
74impl ValidateConfig for SharedEndpointResolver {}
75
76impl_shared_conversions!(convert SharedEndpointResolver from ResolveEndpoint using SharedEndpointResolver::new);
77
78#[derive(Clone, Debug, Eq, PartialEq)]
80pub struct EndpointPrefix(String);
81impl EndpointPrefix {
82 pub fn new(prefix: impl Into<String>) -> Result<Self, InvalidEndpointError> {
85 let prefix = prefix.into();
86 match Authority::from_str(&prefix) {
87 Ok(_) => Ok(EndpointPrefix(prefix)),
88 Err(err) => Err(InvalidEndpointError::failed_to_construct_authority(
89 prefix, err,
90 )),
91 }
92 }
93
94 pub fn as_str(&self) -> &str {
96 &self.0
97 }
98}
99
100impl Storable for EndpointPrefix {
101 type Storer = StoreReplace<Self>;
102}
103
104pub mod error {
106 use crate::box_error::BoxError;
107 use std::error::Error as StdError;
108 use std::fmt;
109
110 #[derive(Debug)]
112 pub struct ResolveEndpointError {
113 message: String,
114 source: Option<BoxError>,
115 }
116
117 impl ResolveEndpointError {
118 pub fn message(message: impl Into<String>) -> Self {
120 Self {
121 message: message.into(),
122 source: None,
123 }
124 }
125
126 pub fn with_source(self, source: Option<BoxError>) -> Self {
128 Self { source, ..self }
129 }
130
131 pub fn from_source(message: impl Into<String>, source: impl Into<BoxError>) -> Self {
133 Self::message(message).with_source(Some(source.into()))
134 }
135 }
136
137 impl fmt::Display for ResolveEndpointError {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 write!(f, "{}", self.message)
140 }
141 }
142
143 impl StdError for ResolveEndpointError {
144 fn source(&self) -> Option<&(dyn StdError + 'static)> {
145 self.source.as_ref().map(|err| err.as_ref() as _)
146 }
147 }
148
149 #[derive(Debug)]
150 pub(super) enum InvalidEndpointErrorKind {
151 EndpointMustHaveScheme,
152 FailedToConstructAuthority { authority: String, source: BoxError },
153 FailedToConstructUri { source: BoxError },
154 }
155
156 #[derive(Debug)]
159 pub struct InvalidEndpointError {
160 pub(super) kind: InvalidEndpointErrorKind,
161 }
162
163 impl InvalidEndpointError {
164 pub fn endpoint_must_have_scheme() -> Self {
166 Self {
167 kind: InvalidEndpointErrorKind::EndpointMustHaveScheme,
168 }
169 }
170
171 pub fn failed_to_construct_authority(
173 authority: impl Into<String>,
174 source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
175 ) -> Self {
176 Self {
177 kind: InvalidEndpointErrorKind::FailedToConstructAuthority {
178 authority: authority.into(),
179 source: source.into(),
180 },
181 }
182 }
183
184 pub fn failed_to_construct_uri(
186 source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
187 ) -> Self {
188 Self {
189 kind: InvalidEndpointErrorKind::FailedToConstructUri {
190 source: source.into(),
191 },
192 }
193 }
194 }
195
196 impl From<InvalidEndpointErrorKind> for InvalidEndpointError {
197 fn from(kind: InvalidEndpointErrorKind) -> Self {
198 Self { kind }
199 }
200 }
201
202 impl fmt::Display for InvalidEndpointError {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 use InvalidEndpointErrorKind as ErrorKind;
205 match &self.kind {
206 ErrorKind::EndpointMustHaveScheme => write!(f, "endpoint must contain a valid scheme"),
207 ErrorKind::FailedToConstructAuthority { authority, source: _ } => write!(
208 f,
209 "endpoint must contain a valid authority when combined with endpoint prefix: {authority}"
210 ),
211 ErrorKind::FailedToConstructUri { .. } => write!(f, "failed to construct URI"),
212 }
213 }
214 }
215
216 impl StdError for InvalidEndpointError {
217 fn source(&self) -> Option<&(dyn StdError + 'static)> {
218 use InvalidEndpointErrorKind as ErrorKind;
219 match &self.kind {
220 ErrorKind::FailedToConstructUri { source } => Some(source.as_ref()),
221 ErrorKind::FailedToConstructAuthority {
222 authority: _,
223 source,
224 } => Some(source.as_ref()),
225 ErrorKind::EndpointMustHaveScheme => None,
226 }
227 }
228 }
229}