Skip to content

Commit f57e16a

Browse files
ysaito1001unexge
authored andcommitted
Follow up on DefaultEndpointResolver in the orchestrator (#2592)
## Motivation and Context This PR incorporates post-merge feedback left in #2577. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Co-authored-by: Yuki Saito <[email protected]>
1 parent a593757 commit f57e16a

File tree

9 files changed

+143
-124
lines changed

9 files changed

+143
-124
lines changed

aws/sra-test/integration-tests/aws-sdk-s3/tests/sra_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use aws_sdk_s3::primitives::SdkBody;
1717
use aws_smithy_client::erase::DynConnector;
1818
use aws_smithy_client::test_connection::TestConnection;
1919
use aws_smithy_runtime::client::connections::adapter::DynConnectorAdapter;
20-
use aws_smithy_runtime_api::client::endpoints::DefaultEndpointResolver;
20+
use aws_smithy_runtime::client::orchestrator::endpoints::DefaultEndpointResolver;
2121
use aws_smithy_runtime_api::client::interceptors::{
2222
Interceptor, InterceptorContext, InterceptorError, Interceptors,
2323
};

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsInterceptorGenerator.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class EndpointParamsInterceptorGenerator(
3232
arrayOf(
3333
"BoxError" to runtimeApi.resolve("client::runtime_plugin::BoxError"),
3434
"ConfigBag" to runtimeApi.resolve("config_bag::ConfigBag"),
35+
"ContextAttachedError" to interceptors.resolve("error::ContextAttachedError"),
3536
"EndpointResolverParams" to orchestrator.resolve("EndpointResolverParams"),
3637
"HttpResponse" to orchestrator.resolve("HttpResponse"),
3738
"HttpRequest" to orchestrator.resolve("HttpRequest"),
@@ -83,10 +84,10 @@ class EndpointParamsInterceptorGenerator(
8384
let input = context.input()?;
8485
let _input = input
8586
.downcast_ref::<${operationInput.name}>()
86-
.ok_or_else(|| #{InterceptorError}::invalid_input_access())?;
87+
.ok_or_else(|| "failed to downcast to ${operationInput.name}")?;
8788
let params_builder = cfg
8889
.get::<#{ParamsBuilder}>()
89-
.ok_or(#{InterceptorError}::read_before_execution("missing endpoint params builder"))?
90+
.ok_or_else(|| "missing endpoint params builder")?
9091
.clone();
9192
${"" /* TODO(EndpointResolver): Call setters on `params_builder` to update its fields by using values from `_input` */}
9293
cfg.put(params_builder);
@@ -111,7 +112,7 @@ class EndpointParamsInterceptorGenerator(
111112
)
112113
withBlockTemplate(
113114
"let endpoint_prefix = ",
114-
".map_err(#{InterceptorError}::read_before_execution)?;",
115+
""".map_err(|err| #{ContextAttachedError}::new("endpoint prefix could not be built", err))?;""",
115116
*codegenScope,
116117
) {
117118
endpointTraitBindings.render(
@@ -130,11 +131,11 @@ class EndpointParamsInterceptorGenerator(
130131
let _ = context;
131132
let params_builder = cfg
132133
.get::<#{ParamsBuilder}>()
133-
.ok_or(#{InterceptorError}::read_before_execution("missing endpoint params builder"))?
134+
.ok_or_else(|| "missing endpoint params builder")?
134135
.clone();
135136
let params = params_builder
136137
.build()
137-
.map_err(#{InterceptorError}::read_before_execution)?;
138+
.map_err(|err| #{ContextAttachedError}::new("endpoint params could not be built", err))?;
138139
cfg.put(
139140
#{EndpointResolverParams}::new(params)
140141
);

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class ServiceRuntimePluginGenerator(
8686
"ConfigBagAccessors" to runtimeApi.resolve("client::orchestrator::ConfigBagAccessors"),
8787
"Connection" to runtimeApi.resolve("client::orchestrator::Connection"),
8888
"ConnectorSettings" to RuntimeType.smithyClient(rc).resolve("http_connector::ConnectorSettings"),
89-
"DefaultEndpointResolver" to runtimeApi.resolve("client::endpoints::DefaultEndpointResolver"),
89+
"DefaultEndpointResolver" to runtime.resolve("client::orchestrator::endpoints::DefaultEndpointResolver"),
9090
"DynConnectorAdapter" to runtime.resolve("client::connections::adapter::DynConnectorAdapter"),
9191
"HttpAuthSchemes" to runtimeApi.resolve("client::orchestrator::HttpAuthSchemes"),
9292
"IdentityResolvers" to runtimeApi.resolve("client::orchestrator::IdentityResolvers"),

rust-runtime/aws-smithy-runtime-api/src/client.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,5 @@ pub mod retries;
2121
/// Runtime plugin type definitions.
2222
pub mod runtime_plugin;
2323

24-
/// Smithy endpoint resolution runtime plugins
25-
pub mod endpoints;
26-
2724
/// Smithy auth runtime plugins
2825
pub mod auth;

rust-runtime/aws-smithy-runtime-api/src/client/endpoints.rs

Lines changed: 0 additions & 110 deletions
This file was deleted.

rust-runtime/aws-smithy-runtime-api/src/client/interceptors/error.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,31 @@ impl std::error::Error for InterceptorError {
169169
self.source.as_ref().map(|err| err.as_ref() as _)
170170
}
171171
}
172+
173+
/// A convenience error that allows for adding additional `context` to `source`
174+
#[derive(Debug)]
175+
pub struct ContextAttachedError {
176+
context: String,
177+
source: Option<BoxError>,
178+
}
179+
180+
impl ContextAttachedError {
181+
pub fn new(context: impl Into<String>, source: impl Into<BoxError>) -> Self {
182+
Self {
183+
context: context.into(),
184+
source: Some(source.into()),
185+
}
186+
}
187+
}
188+
189+
impl fmt::Display for ContextAttachedError {
190+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191+
write!(f, "{}", self.context)
192+
}
193+
}
194+
195+
impl std::error::Error for ContextAttachedError {
196+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
197+
self.source.as_ref().map(|err| err.as_ref() as _)
198+
}
199+
}

rust-runtime/aws-smithy-runtime/external-types.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ allowed_external_types = [
66
"http::header::name::HeaderName",
77
"http::request::Request",
88
"http::response::Response",
9-
"uri::Uri",
9+
"http::uri::Uri",
1010
]

rust-runtime/aws-smithy-runtime/src/client/orchestrator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ use aws_smithy_runtime_api::config_bag::ConfigBag;
1818
use tracing::{debug_span, Instrument};
1919

2020
mod auth;
21-
mod endpoints;
21+
/// Defines types that implement a trait for endpoint resolution
22+
pub mod endpoints;
2223
mod http;
2324
pub(self) mod phase;
2425

rust-runtime/aws-smithy-runtime/src/client/orchestrator/endpoints.rs

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,114 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
use aws_smithy_http::endpoint::EndpointPrefix;
6+
use aws_smithy_http::endpoint::error::ResolveEndpointError;
7+
use aws_smithy_http::endpoint::{
8+
apply_endpoint, EndpointPrefix, ResolveEndpoint, SharedEndpointResolver,
9+
};
710
use aws_smithy_runtime_api::client::interceptors::InterceptorContext;
811
use aws_smithy_runtime_api::client::orchestrator::{
9-
BoxError, ConfigBagAccessors, HttpRequest, HttpResponse,
12+
BoxError, ConfigBagAccessors, EndpointResolver, EndpointResolverParams, HttpRequest,
13+
HttpResponse,
1014
};
1115
use aws_smithy_runtime_api::config_bag::ConfigBag;
16+
use http::header::HeaderName;
17+
use http::{HeaderValue, Uri};
18+
use std::fmt::Debug;
19+
use std::str::FromStr;
20+
21+
#[derive(Debug, Clone)]
22+
pub struct StaticUriEndpointResolver {
23+
endpoint: Uri,
24+
}
25+
26+
impl StaticUriEndpointResolver {
27+
pub fn http_localhost(port: u16) -> Self {
28+
Self {
29+
endpoint: Uri::from_str(&format!("http://localhost:{port}"))
30+
.expect("all u16 values are valid ports"),
31+
}
32+
}
33+
34+
pub fn uri(endpoint: Uri) -> Self {
35+
Self { endpoint }
36+
}
37+
}
38+
39+
impl EndpointResolver for StaticUriEndpointResolver {
40+
fn resolve_and_apply_endpoint(
41+
&self,
42+
_params: &EndpointResolverParams,
43+
_endpoint_prefix: Option<&EndpointPrefix>,
44+
request: &mut HttpRequest,
45+
) -> Result<(), BoxError> {
46+
apply_endpoint(request.uri_mut(), &self.endpoint, None)?;
47+
Ok(())
48+
}
49+
}
50+
51+
#[derive(Debug, Clone)]
52+
pub struct DefaultEndpointResolver<Params> {
53+
inner: SharedEndpointResolver<Params>,
54+
}
55+
56+
impl<Params> DefaultEndpointResolver<Params> {
57+
pub fn new(resolve_endpoint: SharedEndpointResolver<Params>) -> Self {
58+
Self {
59+
inner: resolve_endpoint,
60+
}
61+
}
62+
}
63+
64+
impl<Params> EndpointResolver for DefaultEndpointResolver<Params>
65+
where
66+
Params: Debug + Send + Sync + 'static,
67+
{
68+
fn resolve_and_apply_endpoint(
69+
&self,
70+
params: &EndpointResolverParams,
71+
endpoint_prefix: Option<&EndpointPrefix>,
72+
request: &mut HttpRequest,
73+
) -> Result<(), BoxError> {
74+
let endpoint = match params.get::<Params>() {
75+
Some(params) => self.inner.resolve_endpoint(params)?,
76+
None => {
77+
return Err(Box::new(ResolveEndpointError::message(
78+
"params of expected type was not present",
79+
)));
80+
}
81+
};
82+
83+
let uri: Uri = endpoint.url().parse().map_err(|err| {
84+
ResolveEndpointError::from_source("endpoint did not have a valid uri", err)
85+
})?;
86+
87+
apply_endpoint(request.uri_mut(), &uri, endpoint_prefix).map_err(|err| {
88+
ResolveEndpointError::message(format!(
89+
"failed to apply endpoint `{:?}` to request `{:?}`",
90+
uri, request,
91+
))
92+
.with_source(Some(err.into()))
93+
})?;
94+
95+
for (header_name, header_values) in endpoint.headers() {
96+
request.headers_mut().remove(header_name);
97+
for value in header_values {
98+
request.headers_mut().insert(
99+
HeaderName::from_str(header_name).map_err(|err| {
100+
ResolveEndpointError::message("invalid header name")
101+
.with_source(Some(err.into()))
102+
})?,
103+
HeaderValue::from_str(value).map_err(|err| {
104+
ResolveEndpointError::message("invalid header value")
105+
.with_source(Some(err.into()))
106+
})?,
107+
);
108+
}
109+
}
110+
111+
Ok(())
112+
}
113+
}
12114

13115
pub(super) fn orchestrate_endpoint(
14116
ctx: &mut InterceptorContext<HttpRequest, HttpResponse>,

0 commit comments

Comments
 (0)