aws_smithy_runtime_api/client/
endpoint.rs1use 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::any::TypeId;
17use std::collections::HashMap;
18use std::fmt;
19use std::str::FromStr;
20use std::sync::Arc;
21
22new_type_future! {
23 #[doc = "Future for [`ResolveEndpoint::resolve_endpoint`]."]
24 pub struct EndpointFuture<'a, Endpoint, BoxError>;
25}
26
27#[derive(Debug)]
37pub struct EndpointResolverParams {
38 inner: TypeErasedBox,
39 property: HashMap<TypeId, TypeErasedBox>,
40}
41
42impl EndpointResolverParams {
43 pub fn new<T: fmt::Debug + Send + Sync + 'static>(params: T) -> Self {
45 Self {
46 inner: TypeErasedBox::new(params),
47 property: HashMap::new(),
48 }
49 }
50
51 pub fn get<T: fmt::Debug + Send + Sync + 'static>(&self) -> Option<&T> {
53 self.inner.downcast_ref()
54 }
55
56 pub fn get_mut<T: fmt::Debug + Send + Sync + 'static>(&mut self) -> Option<&mut T> {
58 self.inner.downcast_mut()
59 }
60
61 pub fn set_property<T: fmt::Debug + Send + Sync + 'static>(&mut self, t: T) {
63 self.property
64 .insert(TypeId::of::<T>(), TypeErasedBox::new(t));
65 }
66
67 pub fn get_property<T: fmt::Debug + Send + Sync + 'static>(&self) -> Option<&T> {
69 self.property
70 .get(&TypeId::of::<T>())
71 .and_then(|b| b.downcast_ref())
72 }
73
74 pub fn get_property_mut<T: fmt::Debug + Send + Sync + 'static>(&mut self) -> Option<&mut T> {
76 self.property
77 .get_mut(&TypeId::of::<T>())
78 .and_then(|b| b.downcast_mut())
79 }
80}
81
82impl Storable for EndpointResolverParams {
83 type Storer = StoreReplace<Self>;
84}
85
86pub trait ResolveEndpoint: Send + Sync + fmt::Debug {
88 fn resolve_endpoint<'a>(&'a self, params: &'a EndpointResolverParams) -> EndpointFuture<'a>;
90
91 fn finalize_params<'a>(
101 &'a self,
102 _params: &'a mut EndpointResolverParams,
103 ) -> Result<(), BoxError> {
104 Ok(())
105 }
106}
107
108#[derive(Clone, Debug)]
112pub struct SharedEndpointResolver(Arc<dyn ResolveEndpoint>);
113
114impl SharedEndpointResolver {
115 pub fn new(endpoint_resolver: impl ResolveEndpoint + 'static) -> Self {
117 Self(Arc::new(endpoint_resolver))
118 }
119}
120
121impl ResolveEndpoint for SharedEndpointResolver {
122 fn resolve_endpoint<'a>(&'a self, params: &'a EndpointResolverParams) -> EndpointFuture<'a> {
123 self.0.resolve_endpoint(params)
124 }
125
126 fn finalize_params<'a>(
127 &'a self,
128 params: &'a mut EndpointResolverParams,
129 ) -> Result<(), BoxError> {
130 self.0.finalize_params(params)
131 }
132}
133
134impl ValidateConfig for SharedEndpointResolver {}
135
136impl_shared_conversions!(convert SharedEndpointResolver from ResolveEndpoint using SharedEndpointResolver::new);
137
138#[derive(Clone, Debug, Eq, PartialEq)]
140pub struct EndpointPrefix(String);
141impl EndpointPrefix {
142 pub fn new(prefix: impl Into<String>) -> Result<Self, InvalidEndpointError> {
145 let prefix = prefix.into();
146 match Authority::from_str(&prefix) {
147 Ok(_) => Ok(EndpointPrefix(prefix)),
148 Err(err) => Err(InvalidEndpointError::failed_to_construct_authority(
149 prefix, err,
150 )),
151 }
152 }
153
154 pub fn as_str(&self) -> &str {
156 &self.0
157 }
158}
159
160impl Storable for EndpointPrefix {
161 type Storer = StoreReplace<Self>;
162}
163
164pub mod error {
166 use crate::box_error::BoxError;
167 use std::error::Error as StdError;
168 use std::fmt;
169
170 #[derive(Debug)]
172 pub struct ResolveEndpointError {
173 message: String,
174 source: Option<BoxError>,
175 }
176
177 impl ResolveEndpointError {
178 pub fn message(message: impl Into<String>) -> Self {
180 Self {
181 message: message.into(),
182 source: None,
183 }
184 }
185
186 pub fn with_source(self, source: Option<BoxError>) -> Self {
188 Self { source, ..self }
189 }
190
191 pub fn from_source(message: impl Into<String>, source: impl Into<BoxError>) -> Self {
193 Self::message(message).with_source(Some(source.into()))
194 }
195 }
196
197 impl fmt::Display for ResolveEndpointError {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(f, "{}", self.message)
200 }
201 }
202
203 impl StdError for ResolveEndpointError {
204 fn source(&self) -> Option<&(dyn StdError + 'static)> {
205 self.source.as_ref().map(|err| err.as_ref() as _)
206 }
207 }
208
209 #[derive(Debug)]
210 pub(super) enum InvalidEndpointErrorKind {
211 EndpointMustHaveScheme,
212 FailedToConstructAuthority { authority: String, source: BoxError },
213 FailedToConstructUri { source: BoxError },
214 }
215
216 #[derive(Debug)]
219 pub struct InvalidEndpointError {
220 pub(super) kind: InvalidEndpointErrorKind,
221 }
222
223 impl InvalidEndpointError {
224 pub fn endpoint_must_have_scheme() -> Self {
226 Self {
227 kind: InvalidEndpointErrorKind::EndpointMustHaveScheme,
228 }
229 }
230
231 pub fn failed_to_construct_authority(
233 authority: impl Into<String>,
234 source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
235 ) -> Self {
236 Self {
237 kind: InvalidEndpointErrorKind::FailedToConstructAuthority {
238 authority: authority.into(),
239 source: source.into(),
240 },
241 }
242 }
243
244 pub fn failed_to_construct_uri(
246 source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
247 ) -> Self {
248 Self {
249 kind: InvalidEndpointErrorKind::FailedToConstructUri {
250 source: source.into(),
251 },
252 }
253 }
254 }
255
256 impl From<InvalidEndpointErrorKind> for InvalidEndpointError {
257 fn from(kind: InvalidEndpointErrorKind) -> Self {
258 Self { kind }
259 }
260 }
261
262 impl fmt::Display for InvalidEndpointError {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 use InvalidEndpointErrorKind as ErrorKind;
265 match &self.kind {
266 ErrorKind::EndpointMustHaveScheme => write!(f, "endpoint must contain a valid scheme"),
267 ErrorKind::FailedToConstructAuthority { authority, source: _ } => write!(
268 f,
269 "endpoint must contain a valid authority when combined with endpoint prefix: {authority}"
270 ),
271 ErrorKind::FailedToConstructUri { .. } => write!(f, "failed to construct URI"),
272 }
273 }
274 }
275
276 impl StdError for InvalidEndpointError {
277 fn source(&self) -> Option<&(dyn StdError + 'static)> {
278 use InvalidEndpointErrorKind as ErrorKind;
279 match &self.kind {
280 ErrorKind::FailedToConstructUri { source } => Some(source.as_ref()),
281 ErrorKind::FailedToConstructAuthority {
282 authority: _,
283 source,
284 } => Some(source.as_ref()),
285 ErrorKind::EndpointMustHaveScheme => None,
286 }
287 }
288 }
289}