diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/auth.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/auth.rs index 5a3482adf1c9fc68e2f5e1e1a0f50eb442cf8ea9..b56b6a744a779539370a4ff944fdbc9d41c5317f 100644 --- a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/auth.rs +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/auth.rs @@ -4,17 +4,25 @@ */ use aws_smithy_http::body::SdkBody; -use aws_smithy_runtime::{AuthOrchestrator, BoxError, ConfigBag}; +use aws_smithy_runtime::{AuthOrchestrator, BoxError}; +use aws_smithy_runtime_api::config_bag::ConfigBag; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugin; #[derive(Debug)] pub struct GetObjectAuthOrc {} impl GetObjectAuthOrc { - pub fn _new() -> Self { + pub fn new() -> Self { Self {} } } +impl RuntimePlugin for GetObjectAuthOrc { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } +} + impl AuthOrchestrator> for GetObjectAuthOrc { fn auth_request( &self, @@ -22,34 +30,30 @@ impl AuthOrchestrator> for GetObjectAuthOrc { _cfg: &ConfigBag, ) -> Result<(), BoxError> { todo!() + + // let signer = SigV4Signer::new(); + // let operation_config = props + // .get::() + // .ok_or("missing signing config".to_string())?; + // + // let (operation_config, request_config, creds) = match &operation_config.signing_requirements + // { + // SigningRequirements::Disabled => return Ok(()), + // SigningRequirements::Optional => { + // match aws_sig_auth::middleware::signing_config(props) { + // Ok(parts) => parts, + // Err(_) => return Ok(()), + // } + // } + // SigningRequirements::Required => { + // aws_sig_auth::middleware::signing_config(props).map_err(Box::new)? + // } + // }; + // + // let _signature = signer + // .sign(&operation_config, &request_config, &creds, req) + // .expect("signing goes just fine"); + // + // Ok(()) } } - -// signer: Arc::new(|req: &mut http::Request, props: &PropertyBag| { -// use aws_smithy_orchestrator::auth::error::Error; -// -// let signer = SigV4Signer::new(); -// let operation_config = props -// .get::() -// .ok_or(Error::SignRequest("missing signing config".into()))?; -// -// let (operation_config, request_config, creds) = match &operation_config -// .signing_requirements -// { -// SigningRequirements::Disabled => return Ok(()), -// SigningRequirements::Optional => { -// match aws_sig_auth::middleware::signing_config(props) { -// Ok(parts) => parts, -// Err(_) => return Ok(()), -// } -// } -// SigningRequirements::Required => aws_sig_auth::middleware::signing_config(props) -// .map_err(|err| Error::SignRequest(Box::new(err)))?, -// }; -// -// let _signature = signer -// .sign(&operation_config, &request_config, &creds, req) -// .expect("signing goes just fine"); -// -// Ok(()) -// }), diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/conn.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/conn.rs index 2d3ca4481a1bc92b70fee41b26bcbf1dee110dab..edf682debb7d9f3093f97c60bb3f4c537832b72d 100644 --- a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/conn.rs +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/conn.rs @@ -6,15 +6,23 @@ use aws_smithy_client::conns::Https; use aws_smithy_client::hyper_ext::Adapter; use aws_smithy_http::body::SdkBody; -use aws_smithy_runtime::{BoxFallibleFut, ConfigBag, Connection}; +use aws_smithy_runtime::{BoxError, BoxFallibleFut, Connection}; +use aws_smithy_runtime_api::config_bag::ConfigBag; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugin; #[derive(Debug)] pub struct HyperConnection { _adapter: Adapter, } +impl RuntimePlugin for HyperConnection { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } +} + impl HyperConnection { - pub fn _new() -> Self { + pub fn new() -> Self { Self { _adapter: Adapter::builder().build(aws_smithy_client::conns::https()), } diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/de.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/de.rs index ac4fa4c04af35149c3a82d7b5b08deb8c2fc7d88..4b0204dd5a04dd1983359617299f09ab392443ea 100644 --- a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/de.rs +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/de.rs @@ -5,17 +5,25 @@ use aws_sdk_s3::operation::get_object::GetObjectOutput; use aws_smithy_http::body::SdkBody; -use aws_smithy_runtime::{BoxError, ConfigBag, ResponseDeserializer}; +use aws_smithy_runtime::{BoxError, ResponseDeserializer}; +use aws_smithy_runtime_api::config_bag::ConfigBag; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugin; #[derive(Debug)] pub struct GetObjectResponseDeserializer {} impl GetObjectResponseDeserializer { - pub fn _new() -> Self { + pub fn new() -> Self { Self {} } } +impl RuntimePlugin for GetObjectResponseDeserializer { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } +} + impl ResponseDeserializer, GetObjectOutput> for GetObjectResponseDeserializer { diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/endpoints.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/endpoints.rs new file mode 100644 index 0000000000000000000000000000000000000000..9874ac3ca2025a3572dd7dd06cc415544a6dabb4 --- /dev/null +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/endpoints.rs @@ -0,0 +1,104 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_smithy_http::body::SdkBody; +use aws_smithy_runtime::{BoxError, EndpointOrchestrator}; +use aws_smithy_runtime_api::config_bag::ConfigBag; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugin; + +#[derive(Debug)] +pub struct GetObjectEndpointOrc {} + +impl GetObjectEndpointOrc { + pub fn new() -> Self { + Self {} + } +} + +impl RuntimePlugin for GetObjectEndpointOrc { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } +} + +impl EndpointOrchestrator> for GetObjectEndpointOrc { + fn resolve_and_apply_endpoint( + &self, + _req: &mut http::Request, + _cfg: &ConfigBag, + ) -> Result<(), BoxError> { + todo!() + // let endpoint = endpoint_resolver.resolve_endpoint(&endpoint_parameters)?; + // let (tx_req, props) = ctx + // .tx_request_mut() + // .expect("We call this after setting the tx request"); + // + // // Apply the endpoint + // let uri: Uri = endpoint.url().parse().map_err(|err| { + // ResolveEndpointError::from_source("endpoint did not have a valid uri", err) + // })?; + // apply_endpoint(tx_req.uri_mut(), &uri, props.get::()).map_err(|err| { + // ResolveEndpointError::message(format!( + // "failed to apply endpoint `{:?}` to request `{:?}`", + // uri, tx_req + // )) + // .with_source(Some(err.into())) + // })?; + // for (header_name, header_values) in endpoint.headers() { + // tx_req.headers_mut().remove(header_name); + // for value in header_values { + // tx_req.headers_mut().insert( + // HeaderName::from_str(header_name).map_err(|err| { + // ResolveEndpointError::message("invalid header name") + // .with_source(Some(err.into())) + // })?, + // HeaderValue::from_str(value).map_err(|err| { + // ResolveEndpointError::message("invalid header value") + // .with_source(Some(err.into())) + // })?, + // ); + // } + // } + } + + fn resolve_auth_schemes(&self) -> Result, BoxError> { + todo!() + + // let endpoint = endpoint_resolver + // .resolve_endpoint(params) + // .map_err(SdkError::construction_failure)?; + // let auth_schemes = match endpoint.properties().get("authSchemes") { + // Some(Document::Array(schemes)) => schemes, + // None => { + // return Ok(vec![]); + // } + // _other => { + // return Err(SdkError::construction_failure( + // "expected bad things".to_string(), + // )); + // } + // }; + // let auth_schemes = auth_schemes + // .iter() + // .flat_map(|doc| match doc { + // Document::Object(map) => Some(map), + // _ => None, + // }) + // .map(|it| { + // let name = match it.get("name") { + // Some(Document::String(s)) => Some(s.as_str()), + // _ => None, + // }; + // AuthSchemeOptions::new( + // name.unwrap().to_string(), + // /* there are no identity properties yet */ + // None, + // Some(Document::Object(it.clone())), + // ) + // }) + // .collect::>(); + // Ok(auth_schemes) + } +} diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/main.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/main.rs index 0b969c8470a7e1acc78f83913edf97179a33dee3..90c372bf866806548e3996546436618a4bc34919 100644 --- a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/main.rs +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/main.rs @@ -6,6 +6,7 @@ mod auth; mod conn; mod de; +mod endpoints; mod interceptors; mod retry; mod ser; @@ -13,8 +14,10 @@ mod ser; use aws_sdk_s3::operation::get_object::{GetObjectInput, GetObjectOutput}; use aws_sdk_s3::types::ChecksumMode; use aws_smithy_http::body::SdkBody; -use aws_smithy_runtime::{invoke, BoxError, ConfigBag}; +use aws_smithy_runtime::{invoke, BoxError}; +use aws_smithy_runtime_api::config_bag::ConfigBag; use aws_smithy_runtime_api::interceptors::Interceptors; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugins; use std::str::from_utf8; use tracing::info; @@ -25,20 +28,25 @@ async fn main() -> Result<(), BoxError> { // Create the config we'll need to send the request + the request itself let sdk_config = aws_config::load_from_env().await; let _service_config = aws_sdk_s3::Config::from(&sdk_config); - // TODO(smithy-orchestrator-codegen) Make it so these are added by default for S3 - // .with_runtime_plugin(auth::GetObjectAuthOrc::new()) - // .with_runtime_plugin(conn::HyperConnection::new()); let input = GetObjectInput::builder() .bucket("zhessler-test-bucket") .key("1000-lines.txt") .checksum_mode(ChecksumMode::Enabled) - // TODO(smithy-orchestrator-codegen) Make it so these are added by default for this S3 operation - // .with_runtime_plugin(retry::GetObjectRetryStrategy::new()) - // .with_runtime_plugin(de::GetObjectResponseDeserializer::new()) - // .with_runtime_plugin(ser::GetObjectInputSerializer::new()) .build()?; + let mut runtime_plugins = RuntimePlugins::new(); + + // TODO(smithy-orchestrator-codegen) Make it so these are added by default for S3 + runtime_plugins + .with_client_plugin(auth::GetObjectAuthOrc::new()) + .with_client_plugin(conn::HyperConnection::new()) + // TODO(smithy-orchestrator-codegen) Make it so these are added by default for this S3 operation + .with_operation_plugin(endpoints::GetObjectEndpointOrc::new()) + .with_operation_plugin(retry::GetObjectRetryStrategy::new()) + .with_operation_plugin(de::GetObjectResponseDeserializer::new()) + .with_operation_plugin(ser::GetObjectInputSerializer::new()); + let mut cfg = ConfigBag::base(); let mut interceptors: Interceptors< GetObjectInput, @@ -46,7 +54,7 @@ async fn main() -> Result<(), BoxError> { http::Response, Result, > = Interceptors::new(); - let res = invoke(input, &mut interceptors, &mut cfg).await?; + let res = invoke(input, &mut interceptors, &runtime_plugins, &mut cfg).await?; let body = res.body.collect().await?.to_vec(); let body_string = from_utf8(&body)?; diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/retry.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/retry.rs index dcb66264585307790e561f744839f4cb53b4d460..8f349cf3aa2e84523264939e8e53a7e7a8fda2c8 100644 --- a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/retry.rs +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/retry.rs @@ -4,24 +4,25 @@ */ use aws_sdk_s3::operation::get_object::{GetObjectError, GetObjectOutput}; -use aws_smithy_runtime::{BoxError, ConfigBag, RetryStrategy}; - -// retry_classifier: Arc::new( -// |res: Result<&SdkSuccess, &SdkError>| -> RetryKind { -// let classifier = AwsResponseRetryClassifier::new(); -// classifier.classify_retry(res) -// }, -// ), +use aws_smithy_runtime::{BoxError, RetryStrategy}; +use aws_smithy_runtime_api::config_bag::ConfigBag; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugin; #[derive(Debug)] pub struct GetObjectRetryStrategy {} impl GetObjectRetryStrategy { - pub fn _new() -> Self { + pub fn new() -> Self { Self {} } } +impl RuntimePlugin for GetObjectRetryStrategy { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } +} + impl RetryStrategy> for GetObjectRetryStrategy { fn should_retry( &self, @@ -31,3 +32,10 @@ impl RetryStrategy> for GetObjectRetrySt todo!() } } + +// retry_classifier: Arc::new( +// |res: Result<&SdkSuccess, &SdkError>| -> RetryKind { +// let classifier = AwsResponseRetryClassifier::new(); +// classifier.classify_retry(res) +// }, +// ), diff --git a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/ser.rs b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/ser.rs index fbfe97510428d93858bcb8e4ab3abe4d255dcca0..43da26129be207026be007ce40d4d96676f9b130 100644 --- a/aws/sdk/integration-tests/aws-smithy-runtime-test/src/ser.rs +++ b/aws/sdk/integration-tests/aws-smithy-runtime-test/src/ser.rs @@ -5,17 +5,25 @@ use aws_sdk_s3::operation::get_object::GetObjectInput; use aws_smithy_http::body::SdkBody; -use aws_smithy_runtime::{BoxError, ConfigBag, RequestSerializer}; +use aws_smithy_runtime::{BoxError, RequestSerializer}; +use aws_smithy_runtime_api::config_bag::ConfigBag; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugin; #[derive(Debug)] pub struct GetObjectInputSerializer {} impl GetObjectInputSerializer { - pub fn _new() -> Self { + pub fn new() -> Self { Self {} } } +impl RuntimePlugin for GetObjectInputSerializer { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } +} + impl RequestSerializer> for GetObjectInputSerializer { fn serialize_request( &self, diff --git a/rust-runtime/aws-smithy-runtime-api/Cargo.toml b/rust-runtime/aws-smithy-runtime-api/Cargo.toml index bb3ef845388fba8bf8a7e87895fb2ec833fe867c..1de8a0e6048241d1252e06b54954b8c155894f88 100644 --- a/rust-runtime/aws-smithy-runtime-api/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime-api/Cargo.toml @@ -12,6 +12,7 @@ publish = false [dependencies] aws-smithy-types = { path = "../aws-smithy-types" } +aws-smithy-http = { path = "../aws-smithy-http" } tokio = { version = "1.25", features = ["sync"] } [package.metadata.docs.rs] diff --git a/rust-runtime/aws-smithy-runtime/src/config_bag.rs b/rust-runtime/aws-smithy-runtime-api/src/config_bag.rs similarity index 100% rename from rust-runtime/aws-smithy-runtime/src/config_bag.rs rename to rust-runtime/aws-smithy-runtime-api/src/config_bag.rs diff --git a/rust-runtime/aws-smithy-runtime-api/src/interceptors.rs b/rust-runtime/aws-smithy-runtime-api/src/interceptors.rs index 06167d54cce2bec3c3196f346e6f4487d9e22b8e..5d4eff539b63ce7ea232d34459f9f82995149109 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/interceptors.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/interceptors.rs @@ -6,6 +6,7 @@ pub mod context; pub mod error; +use crate::config_bag::ConfigBag; pub use context::InterceptorContext; pub use error::InterceptorError; @@ -40,8 +41,10 @@ pub trait Interceptor { fn read_before_execution( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -69,8 +72,10 @@ pub trait Interceptor { fn modify_before_serialization( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -92,8 +97,10 @@ pub trait Interceptor { fn read_before_serialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -115,8 +122,10 @@ pub trait Interceptor { fn read_after_serialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -138,8 +147,10 @@ pub trait Interceptor { fn modify_before_retry_loop( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -166,8 +177,10 @@ pub trait Interceptor { fn read_before_attempt( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -199,8 +212,10 @@ pub trait Interceptor { fn modify_before_signing( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -225,8 +240,10 @@ pub trait Interceptor { fn read_before_signing( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -250,8 +267,10 @@ pub trait Interceptor { fn read_after_signing( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -283,8 +302,10 @@ pub trait Interceptor { fn modify_before_transmit( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -312,8 +333,10 @@ pub trait Interceptor { fn read_before_transmit( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -341,8 +364,10 @@ pub trait Interceptor { fn read_after_transmit( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -374,8 +399,10 @@ pub trait Interceptor { fn modify_before_deserialization( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -402,8 +429,10 @@ pub trait Interceptor { fn read_before_deserialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -430,8 +459,10 @@ pub trait Interceptor { fn read_after_deserialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -460,8 +491,10 @@ pub trait Interceptor { fn modify_before_attempt_completion( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -490,8 +523,10 @@ pub trait Interceptor { fn read_after_attempt( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -518,8 +553,10 @@ pub trait Interceptor { fn modify_before_completion( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } @@ -544,19 +581,25 @@ pub trait Interceptor { fn read_after_execution( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { let _ctx = context; + let _cfg = cfg; Ok(()) } } pub struct Interceptors { - inner: Vec>>, + client_interceptors: Vec>>, + operation_interceptors: Vec>>, } impl Default for Interceptors { fn default() -> Self { - Self { inner: Vec::new() } + Self { + client_interceptors: Vec::new(), + operation_interceptors: Vec::new(), + } } } @@ -565,21 +608,48 @@ impl Interceptors { Self::default() } - // pub fn with_interceptor( - // &mut self, - // interceptor: impl Interceptor, - // ) -> &mut Self { - // self.inner.push(Box::new(interceptor)); - // - // self - // } + pub fn with_client_interceptor( + &mut self, + interceptor: impl Interceptor + 'static, + ) -> &mut Self { + self.client_interceptors.push(Box::new(interceptor)); + self + } + + pub fn with_operation_interceptor( + &mut self, + interceptor: impl Interceptor + 'static, + ) -> &mut Self { + self.operation_interceptors.push(Box::new(interceptor)); + self + } + + fn all_interceptors_mut( + &mut self, + ) -> impl Iterator>> { + self.client_interceptors + .iter_mut() + .chain(self.operation_interceptors.iter_mut()) + } + + pub fn client_read_before_execution( + &mut self, + context: &InterceptorContext, + cfg: &mut ConfigBag, + ) -> Result<(), InterceptorError> { + for interceptor in self.client_interceptors.iter_mut() { + interceptor.read_before_execution(context, cfg)?; + } + Ok(()) + } - pub fn read_before_execution( + pub fn operation_read_before_execution( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_before_execution(context)?; + for interceptor in self.operation_interceptors.iter_mut() { + interceptor.read_before_execution(context, cfg)?; } Ok(()) } @@ -587,9 +657,10 @@ impl Interceptors { pub fn modify_before_serialization( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_serialization(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_serialization(context, cfg)?; } Ok(()) @@ -598,9 +669,10 @@ impl Interceptors { pub fn read_before_serialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_before_serialization(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_before_serialization(context, cfg)?; } Ok(()) } @@ -608,9 +680,10 @@ impl Interceptors { pub fn read_after_serialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_after_serialization(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_after_serialization(context, cfg)?; } Ok(()) } @@ -618,9 +691,10 @@ impl Interceptors { pub fn modify_before_retry_loop( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_retry_loop(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_retry_loop(context, cfg)?; } Ok(()) @@ -629,9 +703,10 @@ impl Interceptors { pub fn read_before_attempt( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_before_attempt(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_before_attempt(context, cfg)?; } Ok(()) } @@ -639,9 +714,10 @@ impl Interceptors { pub fn modify_before_signing( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_signing(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_signing(context, cfg)?; } Ok(()) @@ -650,9 +726,10 @@ impl Interceptors { pub fn read_before_signing( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_before_signing(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_before_signing(context, cfg)?; } Ok(()) } @@ -660,9 +737,10 @@ impl Interceptors { pub fn read_after_signing( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_after_signing(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_after_signing(context, cfg)?; } Ok(()) } @@ -670,9 +748,10 @@ impl Interceptors { pub fn modify_before_transmit( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_transmit(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_transmit(context, cfg)?; } Ok(()) @@ -681,9 +760,10 @@ impl Interceptors { pub fn read_before_transmit( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_before_transmit(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_before_transmit(context, cfg)?; } Ok(()) } @@ -691,9 +771,10 @@ impl Interceptors { pub fn read_after_transmit( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_after_transmit(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_after_transmit(context, cfg)?; } Ok(()) } @@ -701,9 +782,10 @@ impl Interceptors { pub fn modify_before_deserialization( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_deserialization(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_deserialization(context, cfg)?; } Ok(()) @@ -712,9 +794,10 @@ impl Interceptors { pub fn read_before_deserialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_before_deserialization(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_before_deserialization(context, cfg)?; } Ok(()) } @@ -722,9 +805,10 @@ impl Interceptors { pub fn read_after_deserialization( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_after_deserialization(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_after_deserialization(context, cfg)?; } Ok(()) } @@ -732,9 +816,10 @@ impl Interceptors { pub fn modify_before_attempt_completion( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_attempt_completion(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_attempt_completion(context, cfg)?; } Ok(()) @@ -743,9 +828,10 @@ impl Interceptors { pub fn read_after_attempt( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_after_attempt(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_after_attempt(context, cfg)?; } Ok(()) } @@ -753,9 +839,10 @@ impl Interceptors { pub fn modify_before_completion( &mut self, context: &mut InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.modify_before_completion(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.modify_before_completion(context, cfg)?; } Ok(()) @@ -764,9 +851,10 @@ impl Interceptors { pub fn read_after_execution( &mut self, context: &InterceptorContext, + cfg: &mut ConfigBag, ) -> Result<(), InterceptorError> { - for interceptor in self.inner.iter_mut() { - interceptor.read_after_execution(context)?; + for interceptor in self.all_interceptors_mut() { + interceptor.read_after_execution(context, cfg)?; } Ok(()) } diff --git a/rust-runtime/aws-smithy-runtime-api/src/interceptors/context.rs b/rust-runtime/aws-smithy-runtime-api/src/interceptors/context.rs index 1572a9deaf74602ddb1ba6e0380be8083f824e5f..64fb781b328d1feb5ba37de84fbcba9837a5ff04 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/interceptors/context.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/interceptors/context.rs @@ -11,7 +11,6 @@ pub struct InterceptorContext { tx_request: Option, modeled_response: Option, tx_response: Option, - inner_context: Option>>, } // TODO(interceptors) we could use types to ensure that people calling methods on interceptor context can't access @@ -23,15 +22,9 @@ impl InterceptorContext bool { - self.inner_context.is_some() - } - /// Retrieve the modeled request for the operation being invoked. pub fn modeled_request(&self) -> &ModReq { &self.modeled_request @@ -45,31 +38,17 @@ impl InterceptorContext Result<&TxReq, InterceptorError> { - match ( - &self.tx_request, - self.inner_context - .as_ref() - .and_then(|inner| inner.tx_request.as_ref()), - ) { - (Some(req), _) => Ok(req), - (None, Some(req)) => Ok(req), - (None, _) => Err(InterceptorError::invalid_tx_request_access()), - } + self.tx_request + .as_ref() + .ok_or_else(InterceptorError::invalid_tx_request_access) } /// Retrieve the transmittable request for the operation being invoked. /// This will only be available once request marshalling has completed. pub fn tx_request_mut(&mut self) -> Result<&mut TxReq, InterceptorError> { - match ( - &mut self.tx_request, - self.inner_context - .as_mut() - .and_then(|inner| inner.tx_request.as_mut()), - ) { - (Some(req), _) => Ok(req), - (None, Some(req)) => Ok(req), - (None, _) => Err(InterceptorError::invalid_tx_request_access()), - } + self.tx_request + .as_mut() + .ok_or_else(InterceptorError::invalid_tx_request_access) } /// Retrieve the response to the transmittable request for the operation @@ -144,32 +123,4 @@ impl InterceptorContext Self { - match self.inner_context { - Some(inner) => *inner, - None => self, - } - } - - pub fn save(self) -> Self { - todo!() - - // Self { - // // These are `None` because we'd need to clone them and there's no point doing that - // // until we need to modify them. Maybe we should use `Cow`s then? - // modeled_request: self.modeled_request.clone(), - // tx_request: None, - // tx_response: None, - // modeled_response: None, - // inner_context: Some(Box::new(self)), - // } - } - - // This is to help Zelda avoid thinking about how to do the layering of InterceptorContext. Don't - // depend on this unless you can come to terms with its eventual removal. - pub fn reset(&mut self) { - self.tx_response = None; - self.modeled_response = None; - } } diff --git a/rust-runtime/aws-smithy-runtime-api/src/lib.rs b/rust-runtime/aws-smithy-runtime-api/src/lib.rs index 7449e4232c84a7fac64e293de0b368269a24ee29..0ccdd53f065ef4c6a43c870a1cc08cc068d34329 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/lib.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/lib.rs @@ -12,6 +12,8 @@ //! Basic types for the new smithy client orchestrator. +/// A typemap for storing configuration. +pub mod config_bag; /// Smithy interceptors for smithy clients. /// /// Interceptors are lifecycle hooks that can read/modify requests and responses. @@ -21,3 +23,5 @@ pub mod interceptors; /// This code defines when and how failed requests should be retried. It also defines the behavior /// used to limit the rate that requests are sent. pub mod retries; +/// Runtime plugin type definitions. +pub mod runtime_plugin; diff --git a/rust-runtime/aws-smithy-runtime-api/src/runtime_plugin.rs b/rust-runtime/aws-smithy-runtime-api/src/runtime_plugin.rs new file mode 100644 index 0000000000000000000000000000000000000000..f29de78e0bc8a4eea8965f64f6fc9faeff5bdcf7 --- /dev/null +++ b/rust-runtime/aws-smithy-runtime-api/src/runtime_plugin.rs @@ -0,0 +1,85 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::config_bag::ConfigBag; + +type BoxError = Box; + +pub trait RuntimePlugin { + fn configure(&self, cfg: &mut ConfigBag) -> Result<(), BoxError>; +} + +impl From for Box +where + T: RuntimePlugin + 'static, +{ + fn from(t: T) -> Self { + Box::new(t) as _ + } +} + +#[derive(Default)] +pub struct RuntimePlugins { + client_plugins: Vec>, + operation_plugins: Vec>, +} + +impl RuntimePlugins { + pub fn new() -> Self { + Default::default() + } + + pub fn with_client_plugin( + &mut self, + plugin: impl Into>, + ) -> &mut Self { + self.client_plugins.push(plugin.into()); + self + } + + pub fn with_operation_plugin( + &mut self, + plugin: impl Into>, + ) -> &mut Self { + self.operation_plugins.push(plugin.into()); + self + } + + pub fn apply_client_configuration(&self, cfg: &mut ConfigBag) -> Result<(), BoxError> { + for plugin in self.client_plugins.iter() { + plugin.configure(cfg)?; + } + + Ok(()) + } + + pub fn apply_operation_configuration(&self, cfg: &mut ConfigBag) -> Result<(), BoxError> { + for plugin in self.operation_plugins.iter() { + plugin.configure(cfg)?; + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::{BoxError, RuntimePlugin, RuntimePlugins}; + use crate::config_bag::ConfigBag; + + struct SomeStruct; + + impl RuntimePlugin for SomeStruct { + fn configure(&self, _cfg: &mut ConfigBag) -> Result<(), BoxError> { + todo!() + } + } + + #[test] + fn can_add_runtime_plugin_implementors_to_runtime_plugins() { + let mut rps = RuntimePlugins::new(); + rps.with_client_plugin(SomeStruct); + } +} diff --git a/rust-runtime/aws-smithy-runtime/src/lib.rs b/rust-runtime/aws-smithy-runtime/src/lib.rs index 47887330db0b1acc3401189ea129c9e508f1f767..b4d85b5ed8c0e4f667c4d44816abdd28bf12c45a 100644 --- a/rust-runtime/aws-smithy-runtime/src/lib.rs +++ b/rust-runtime/aws-smithy-runtime/src/lib.rs @@ -10,11 +10,9 @@ rust_2018_idioms )] -pub mod config_bag; - -pub use crate::config_bag::ConfigBag; -use aws_smithy_http::body::SdkBody; +use aws_smithy_runtime_api::config_bag::ConfigBag; use aws_smithy_runtime_api::interceptors::{InterceptorContext, Interceptors}; +use aws_smithy_runtime_api::runtime_plugin::RuntimePlugins; use std::fmt::Debug; use std::future::Future; use std::pin::Pin; @@ -48,6 +46,8 @@ pub trait AuthOrchestrator: Send + Sync + Debug { pub trait EndpointOrchestrator: Send + Sync + Debug { fn resolve_and_apply_endpoint(&self, req: &mut Req, cfg: &ConfigBag) -> Result<(), BoxError>; + // TODO(jdisanti) The EP Orc and Auth Orc need to share info on auth schemes but I'm not sure how that should happen + fn resolve_auth_schemes(&self) -> Result, BoxError>; } /// `In`: The input message e.g. `ListObjectsRequest` @@ -59,6 +59,7 @@ pub trait EndpointOrchestrator: Send + Sync + Debug { pub async fn invoke( input: In, interceptors: &mut Interceptors>, + runtime_plugins: &RuntimePlugins, cfg: &mut ConfigBag, ) -> Result where @@ -70,13 +71,15 @@ where { let mut ctx: InterceptorContext> = InterceptorContext::new(input); - // 1 - // // TODO(runtime-plugins) initialize runtime plugins (see section 3.11 "Runtime Plugins and Their Configuration" of SRA) - // let cfg = cfg.clone().apply_plugins(); - interceptors.read_before_execution(&ctx)?; - interceptors.modify_before_serialization(&mut ctx)?; - interceptors.read_before_serialization(&ctx)?; + runtime_plugins.apply_client_configuration(cfg)?; + interceptors.client_read_before_execution(&ctx, cfg)?; + + runtime_plugins.apply_operation_configuration(cfg)?; + interceptors.operation_read_before_execution(&ctx, cfg)?; + + interceptors.read_before_serialization(&ctx, cfg)?; + interceptors.modify_before_serialization(&mut ctx, cfg)?; let request_serializer = cfg .get::>>() @@ -84,13 +87,13 @@ where let req = request_serializer.serialize_request(ctx.modeled_request_mut(), cfg)?; ctx.set_tx_request(req); - interceptors.read_after_serialization(&ctx)?; - interceptors.modify_before_retry_loop(&mut ctx)?; + interceptors.read_after_serialization(&ctx, cfg)?; + interceptors.modify_before_retry_loop(&mut ctx, cfg)?; loop { make_an_attempt(&mut ctx, cfg, interceptors).await?; - interceptors.read_after_attempt(&ctx)?; - interceptors.modify_before_attempt_completion(&mut ctx)?; + interceptors.read_after_attempt(&ctx, cfg)?; + interceptors.modify_before_attempt_completion(&mut ctx, cfg)?; let retry_strategy = cfg .get::>>>() @@ -102,12 +105,12 @@ where continue; } - interceptors.modify_before_completion(&mut ctx)?; + interceptors.modify_before_completion(&mut ctx, cfg)?; let trace_probe = cfg .get::>() .ok_or("missing trace probes")?; trace_probe.dispatch_events(cfg); - interceptors.read_after_execution(&ctx)?; + interceptors.read_after_execution(&ctx, cfg)?; break; } @@ -116,36 +119,6 @@ where modeled_response } -pub fn try_clone_http_request(req: &http::Request) -> Option> { - let cloned_body = req.body().try_clone()?; - let mut cloned_request = http::Request::builder() - .uri(req.uri().clone()) - .method(req.method()); - *cloned_request - .headers_mut() - .expect("builder has not been modified, headers must be valid") = req.headers().clone(); - let req = cloned_request - .body(cloned_body) - .expect("a clone of a valid request should be a valid request"); - - Some(req) -} - -pub fn try_clone_http_response(res: &http::Response) -> Option> { - let cloned_body = res.body().try_clone()?; - let mut cloned_response = http::Response::builder() - .version(res.version()) - .status(res.status()); - *cloned_response - .headers_mut() - .expect("builder has not been modified, headers must be valid") = res.headers().clone(); - let res = cloned_response - .body(cloned_body) - .expect("a clone of a valid response should be a valid request"); - - Some(res) -} - // Making an HTTP request can fail for several reasons, but we still need to // call lifecycle events when that happens. Therefore, we define this // `make_an_attempt` function to make error handling simpler. @@ -160,7 +133,7 @@ where Res: 'static, T: 'static, { - interceptors.read_before_attempt(ctx)?; + interceptors.read_before_attempt(ctx, cfg)?; let tx_req_mut = ctx.tx_request_mut().expect("tx_request has been set"); let endpoint_orchestrator = cfg @@ -168,8 +141,8 @@ where .ok_or("missing endpoint orchestrator")?; endpoint_orchestrator.resolve_and_apply_endpoint(tx_req_mut, cfg)?; - interceptors.modify_before_signing(ctx)?; - interceptors.read_before_signing(ctx)?; + interceptors.modify_before_signing(ctx, cfg)?; + interceptors.read_before_signing(ctx, cfg)?; let tx_req_mut = ctx.tx_request_mut().expect("tx_request has been set"); let auth_orchestrator = cfg @@ -177,13 +150,12 @@ where .ok_or("missing auth orchestrator")?; auth_orchestrator.auth_request(tx_req_mut, cfg)?; - interceptors.read_after_signing(ctx)?; - interceptors.modify_before_transmit(ctx)?; - interceptors.read_before_transmit(ctx)?; + interceptors.read_after_signing(ctx, cfg)?; + interceptors.modify_before_transmit(ctx, cfg)?; + interceptors.read_before_transmit(ctx, cfg)?; // The connection consumes the request but we need to keep a copy of it // within the interceptor context, so we clone it here. - let res = { let tx_req = ctx.tx_request_mut().expect("tx_request has been set"); let connection = cfg @@ -193,9 +165,9 @@ where }; ctx.set_tx_response(res); - interceptors.read_after_transmit(ctx)?; - interceptors.modify_before_deserialization(ctx)?; - interceptors.read_before_deserialization(ctx)?; + interceptors.read_after_transmit(ctx, cfg)?; + interceptors.modify_before_deserialization(ctx, cfg)?; + interceptors.read_before_deserialization(ctx, cfg)?; let tx_res = ctx.tx_response_mut().expect("tx_response has been set"); let response_deserializer = cfg .get::>>>() @@ -203,7 +175,7 @@ where let res = response_deserializer.deserialize_response(tx_res, cfg)?; ctx.set_modeled_response(res); - interceptors.read_after_deserialization(ctx)?; + interceptors.read_after_deserialization(ctx, cfg)?; Ok(()) }