diff --git a/aws/rust-runtime/aws-inlineable/Cargo.toml b/aws/rust-runtime/aws-inlineable/Cargo.toml index 0b8141b092..6c70fb8e5f 100644 --- a/aws/rust-runtime/aws-inlineable/Cargo.toml +++ b/aws/rust-runtime/aws-inlineable/Cargo.toml @@ -25,7 +25,7 @@ aws-smithy-http-tower = { path = "../../../rust-runtime/aws-smithy-http-tower" } aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client"] } aws-smithy-runtime = { path = "../../../rust-runtime/aws-smithy-runtime", features = ["client"] } aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" } -aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } +aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async", features = ["rt-tokio"] } aws-types = { path = "../aws-types" } bytes = "1" bytes-utils = "0.1.1" @@ -36,7 +36,6 @@ md-5 = "0.10.1" ring = "0.16" tokio = { version = "1.23.1", features = ["full"] } tokio-stream = "0.1.5" -tower = { version = "0.4", default-features = false } tracing = "0.1" [dev-dependencies] diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs index 8cc771b9f6..591d95741d 100644 --- a/aws/rust-runtime/aws-inlineable/src/lib.rs +++ b/aws/rust-runtime/aws-inlineable/src/lib.rs @@ -28,9 +28,6 @@ pub mod no_credentials; /// Support types required for adding presigning to an operation in a generated service. pub mod presigning; -/// Presigning tower service -pub mod presigning_service; - /// Presigning interceptors pub mod presigning_interceptors; @@ -43,9 +40,6 @@ pub mod glacier_checksums; /// Glacier-specific behavior pub mod glacier_interceptors; -/// Default middleware stack for AWS services -pub mod middleware; - /// Strip prefixes from IDs returned by Route53 operations when those IDs are used to construct requests pub mod route53_resource_id_preprocessor_middleware; diff --git a/aws/rust-runtime/aws-inlineable/src/middleware.rs b/aws/rust-runtime/aws-inlineable/src/middleware.rs deleted file mode 100644 index ec66bbbb44..0000000000 --- a/aws/rust-runtime/aws-inlineable/src/middleware.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Base Middleware Stack - -use aws_endpoint::AwsAuthStage; -use aws_http::auth::CredentialsStage; -use aws_http::recursion_detection::RecursionDetectionStage; -use aws_http::user_agent::UserAgentStage; -use aws_sig_auth::middleware::SigV4SigningStage; -use aws_sig_auth::signer::SigV4Signer; -use aws_smithy_http::endpoint::middleware::SmithyEndpointStage; -use aws_smithy_http_tower::map_request::{AsyncMapRequestLayer, MapRequestLayer}; -use std::fmt::Debug; -use tower::ServiceBuilder; - -/// Macro to generate the tower stack type. Arguments should be in reverse order -macro_rules! stack_type { - ($first: ty, $($rest:ty),+) => { - tower::layer::util::Stack<$first, stack_type!($($rest),+)> - }; - ($only: ty) => { - tower::layer::util::Stack<$only, tower::layer::util::Identity> - } -} - -// Note: the layers here appear in reverse order -type DefaultMiddlewareStack = stack_type!( - MapRequestLayer, - MapRequestLayer, - AsyncMapRequestLayer, - MapRequestLayer, - MapRequestLayer, - MapRequestLayer -); - -/// AWS Middleware Stack -/// -/// This implements the middleware stack for this service. It will: -/// 1. Load credentials asynchronously into the property bag -/// 2. Sign the request with SigV4 -/// 3. Resolve an Endpoint for the request -/// 4. Add a user agent to the request -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct DefaultMiddleware; - -impl DefaultMiddleware { - /// Create a new `DefaultMiddleware` stack - /// - /// Note: `DefaultMiddleware` holds no state. - pub fn new() -> Self { - DefaultMiddleware::default() - } -} - -// define the middleware stack in a non-generic location to reduce code bloat. -fn base() -> ServiceBuilder { - let credential_provider = AsyncMapRequestLayer::for_mapper(CredentialsStage::new()); - let signer = MapRequestLayer::for_mapper(SigV4SigningStage::new(SigV4Signer::new())); - let endpoint_stage = MapRequestLayer::for_mapper(SmithyEndpointStage::new()); - let auth_stage = MapRequestLayer::for_mapper(AwsAuthStage); - let user_agent = MapRequestLayer::for_mapper(UserAgentStage::new()); - let recursion_detection = MapRequestLayer::for_mapper(RecursionDetectionStage::new()); - // These layers can be considered as occurring in order, that is: - // 1. Resolve an endpoint - // 2. Add a user agent - // 3. Acquire credentials - // 4. Sign with credentials - // (5. Dispatch over the wire) - ServiceBuilder::new() - .layer(endpoint_stage) - .layer(auth_stage) - .layer(user_agent) - .layer(credential_provider) - .layer(signer) - .layer(recursion_detection) -} - -impl tower::Layer for DefaultMiddleware { - type Service = >::Service; - - fn layer(&self, inner: S) -> Self::Service { - base().service(inner) - } -} diff --git a/aws/rust-runtime/aws-inlineable/src/presigning.rs b/aws/rust-runtime/aws-inlineable/src/presigning.rs index a633352769..f2fa01c2c5 100644 --- a/aws/rust-runtime/aws-inlineable/src/presigning.rs +++ b/aws/rust-runtime/aws-inlineable/src/presigning.rs @@ -174,6 +174,7 @@ impl PresigningConfigBuilder { pub struct PresignedRequest(http::Request<()>); impl PresignedRequest { + #[allow(dead_code)] pub(crate) fn new(inner: http::Request<()>) -> Self { Self(inner) } diff --git a/aws/rust-runtime/aws-inlineable/src/presigning_service.rs b/aws/rust-runtime/aws-inlineable/src/presigning_service.rs deleted file mode 100644 index 3dc1e61768..0000000000 --- a/aws/rust-runtime/aws-inlineable/src/presigning_service.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#![allow(dead_code)] - -//! Tower middleware service for creating presigned requests - -use crate::presigning::PresignedRequest; -use aws_smithy_http::operation; -use http::header::USER_AGENT; -use std::future::{ready, Ready}; -use std::marker::PhantomData; -use std::task::{Context, Poll}; - -/// Tower [`Service`](tower::Service) for generated a [`PresignedRequest`] from the AWS middleware. -#[derive(Default, Debug)] -#[non_exhaustive] -pub(crate) struct PresignedRequestService { - _phantom: PhantomData, -} - -// Required because of the derive Clone on MapRequestService. -// Manually implemented to avoid requiring errors to implement Clone. -impl Clone for PresignedRequestService { - fn clone(&self) -> Self { - Self { - _phantom: Default::default(), - } - } -} - -impl PresignedRequestService { - /// Creates a new `PresignedRequestService` - pub(crate) fn new() -> Self { - Self { - _phantom: Default::default(), - } - } -} - -impl tower::Service for PresignedRequestService { - type Response = PresignedRequest; - type Error = E; - type Future = Ready>; - - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, req: operation::Request) -> Self::Future { - let (mut req, _) = req.into_parts(); - - // Remove user agent headers since the request will not be executed by the AWS Rust SDK. - req.headers_mut().remove(USER_AGENT); - req.headers_mut().remove("X-Amz-User-Agent"); - - ready(Ok(PresignedRequest::new(req.map(|_| ())))) - } -} diff --git a/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs b/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs deleted file mode 100644 index 1c8f0349f2..0000000000 --- a/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use std::convert::Infallible; -use std::error::Error; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::time::{Duration, UNIX_EPOCH}; - -use aws_credential_types::cache::CredentialsCache; -use aws_credential_types::provider::SharedCredentialsProvider; -use aws_credential_types::Credentials; -use aws_smithy_client::erase::DynConnector; -use aws_smithy_client::test_connection::TestConnection; -use aws_smithy_http::body::SdkBody; -use aws_smithy_http::operation; -use aws_smithy_http::operation::Operation; -use aws_smithy_http::response::ParseHttpResponse; -use aws_smithy_types::endpoint::Endpoint; -use aws_smithy_types::retry::{ErrorKind, ProvideErrorKind}; -use bytes::Bytes; -use http::header::{AUTHORIZATION, USER_AGENT}; -use http::{self, Uri}; - -use aws_http::retry::AwsResponseRetryClassifier; -use aws_http::user_agent::AwsUserAgent; -use aws_inlineable::middleware::DefaultMiddleware; -use aws_sig_auth::signer::OperationSigningConfig; -use aws_smithy_async::time::SharedTimeSource; -use aws_types::region::SigningRegion; -use aws_types::SigningName; - -type Client = aws_smithy_client::Client; - -#[derive(Clone)] -struct TestOperationParser; - -#[derive(Debug)] -struct OperationError; - -impl Display for OperationError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl Error for OperationError {} - -impl ProvideErrorKind for OperationError { - fn retryable_error_kind(&self) -> Option { - Some(ErrorKind::ThrottlingError) - } - - fn code(&self) -> Option<&str> { - None - } -} - -impl ParseHttpResponse for TestOperationParser { - type Output = Result; - - fn parse_unloaded(&self, response: &mut operation::Response) -> Option { - if response.http().status().is_success() { - Some(Ok("Hello!".to_string())) - } else { - Some(Err(OperationError)) - } - } - - fn parse_loaded(&self, _response: &http::Response) -> Self::Output { - Ok("Hello!".to_string()) - } -} - -fn test_operation() -> Operation { - let req = operation::Request::new( - http::Request::builder() - .uri("/") - .body(SdkBody::from("request body")) - .unwrap(), - ) - .augment(|req, conf| { - conf.insert(aws_smithy_http::endpoint::Result::Ok( - Endpoint::builder() - .url("https://test-service.test-region.amazonaws.com") - .build(), - )); - aws_http::auth::set_credentials_cache( - conf, - CredentialsCache::lazy().create_cache(SharedCredentialsProvider::new( - Credentials::for_tests_with_session_token(), - )), - ); - conf.insert(SigningRegion::from_static("test-region")); - conf.insert(OperationSigningConfig::default_config()); - conf.insert(SigningName::from_static("test-service-signing")); - conf.insert(SharedTimeSource::new( - UNIX_EPOCH + Duration::from_secs(1613414417), - )); - conf.insert(AwsUserAgent::for_tests()); - Result::<_, Infallible>::Ok(req) - }) - .unwrap(); - Operation::new(req, TestOperationParser) - .with_retry_classifier(AwsResponseRetryClassifier::new()) - .with_metadata(operation::Metadata::new("test-op", "test-service")) -} - -#[cfg(feature = "rustls")] -#[test] -fn test_default_client() { - let client = Client::builder() - .dyn_https_connector(Default::default()) - .middleware_fn(|r| r) - .build(); - let _ = client.call(test_operation()); -} - -#[tokio::test] -async fn e2e_test() { - let expected_req = http::Request::builder() - .header(USER_AGENT, "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0") - .header("x-amz-user-agent", "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0") - .header(AUTHORIZATION, "AWS4-HMAC-SHA256 Credential=ANOTREAL/20210215/test-region/test-service-signing/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=6d477055738c4e634c2451b9fc378b6ff2f967d37657c3dd50a1b6a735576960") - .header("x-amz-date", "20210215T184017Z") - .header("x-amz-security-token", "notarealsessiontoken") - .uri(Uri::from_static("https://test-service.test-region.amazonaws.com/")) - .body(SdkBody::from("request body")).unwrap(); - let events = vec![( - expected_req, - http::Response::builder() - .status(200) - .body("response body") - .unwrap(), - )]; - let conn = TestConnection::new(events); - let client = Client::new(conn.clone()); - let resp = client.call(test_operation()).await; - let resp = resp.expect("successful operation"); - assert_eq!(resp, "Hello!"); - - conn.assert_requests_match(&[]); -} - -#[tokio::test] -async fn test_operation_metadata_is_available_to_middlewares() { - let conn = TestConnection::new(vec![( - http::Request::builder() - .header(USER_AGENT, "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0") - .header("x-amz-user-agent", "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0") - .header(AUTHORIZATION, "AWS4-HMAC-SHA256 Credential=ANOTREAL/20210215/test-region/test-service-signing/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=6d477055738c4e634c2451b9fc378b6ff2f967d37657c3dd50a1b6a735576960") - .header("x-amz-date", "20210215T184017Z") - .header("x-amz-security-token", "notarealsessiontoken") - .uri(Uri::from_static("https://test-service.test-region.amazonaws.com/")) - .body(SdkBody::from("request body")).unwrap(), - http::Response::builder() - .status(200) - .body("response body") - .unwrap(), - )]); - let client = aws_smithy_client::Client::builder() - .middleware_fn(|req| { - let metadata = req - .properties() - .get::() - .cloned() - .unwrap(); - - assert_eq!("test-op", metadata.name()); - assert_eq!("test-service", metadata.service()); - - req - }) - .connector(DynConnector::new(conn)) - .build(); - - let resp = client.call(test_operation()).await; - let resp = resp.expect("successful operation"); - assert_eq!(resp, "Hello!"); -} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt index 88524efefa..8a63872df1 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt @@ -35,7 +35,6 @@ val DECORATORS: List = listOf( RequireEndpointRules(), UserAgentDecorator(), SigV4AuthDecorator(), - SigV4SigningDecorator(), HttpRequestChecksumDecorator(), HttpResponseChecksumDecorator(), RetryClassifierDecorator(), diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCustomizableOperationDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCustomizableOperationDecorator.kt index 8e15437aa3..cd8fe1bef1 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCustomizableOperationDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCustomizableOperationDecorator.kt @@ -84,82 +84,52 @@ class CustomizableOperationTestHelpers(runtimeConfig: RuntimeConfig) : override fun section(section: CustomizableOperationSection): Writable = writable { if (section is CustomizableOperationSection.CustomizableOperationImpl) { - if (section.isRuntimeModeOrchestrator) { - // TODO(enableNewSmithyRuntimeCleanup): Delete these utilities - rustTemplate( - """ - ##[doc(hidden)] - // This is a temporary method for testing. NEVER use it in production - pub fn request_time_for_tests(self, request_time: ::std::time::SystemTime) -> Self { - self.runtime_plugin( - #{StaticRuntimePlugin}::new() - .with_runtime_components( - #{RuntimeComponentsBuilder}::new("request_time_for_tests") - .with_time_source(Some(#{SharedTimeSource}::new(#{StaticTimeSource}::new(request_time)))) - ) - ) - } - - ##[doc(hidden)] - // This is a temporary method for testing. NEVER use it in production - pub fn user_agent_for_tests(mut self) -> Self { - let interceptor = #{TestParamsSetterInterceptor}::new(|context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, _: &mut #{ConfigBag}| { - let headers = context.request_mut().headers_mut(); - let user_agent = #{AwsUserAgent}::for_tests(); - headers.insert( - #{http}::header::USER_AGENT, - #{http}::HeaderValue::try_from(user_agent.ua_header()).unwrap(), - ); - headers.insert( - #{http}::HeaderName::from_static("x-amz-user-agent"), - #{http}::HeaderValue::try_from(user_agent.aws_ua_header()).unwrap(), - ); - }); - self.interceptors.push(#{SharedInterceptor}::new(interceptor)); - self - } + // TODO(enableNewSmithyRuntimeCleanup): Delete these utilities + rustTemplate( + """ + ##[doc(hidden)] + // This is a temporary method for testing. NEVER use it in production + pub fn request_time_for_tests(self, request_time: ::std::time::SystemTime) -> Self { + self.runtime_plugin( + #{StaticRuntimePlugin}::new() + .with_runtime_components( + #{RuntimeComponentsBuilder}::new("request_time_for_tests") + .with_time_source(Some(#{SharedTimeSource}::new(#{StaticTimeSource}::new(request_time)))) + ) + ) + } - ##[doc(hidden)] - // This is a temporary method for testing. NEVER use it in production - pub fn remove_invocation_id_for_tests(mut self) -> Self { - let interceptor = #{TestParamsSetterInterceptor}::new(|context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, _: &mut #{ConfigBag}| { - context.request_mut().headers_mut().remove("amz-sdk-invocation-id"); - }); - self.interceptors.push(#{SharedInterceptor}::new(interceptor)); - self - } - """, - *codegenScope, - ) - } else { - // TODO(enableNewSmithyRuntimeCleanup): Delete this branch when middleware is no longer used - rustTemplate( - """ - ##[doc(hidden)] - // This is a temporary method for testing. NEVER use it in production - pub fn request_time_for_tests(mut self, request_time: ::std::time::SystemTime) -> Self { - self.operation.properties_mut().insert( - #{SharedTimeSource}::new(#{StaticTimeSource}::new(request_time)) + ##[doc(hidden)] + // This is a temporary method for testing. NEVER use it in production + pub fn user_agent_for_tests(mut self) -> Self { + let interceptor = #{TestParamsSetterInterceptor}::new(|context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, _: &mut #{ConfigBag}| { + let headers = context.request_mut().headers_mut(); + let user_agent = #{AwsUserAgent}::for_tests(); + headers.insert( + #{http}::header::USER_AGENT, + #{http}::HeaderValue::try_from(user_agent.ua_header()).unwrap(), ); - self - } - - ##[doc(hidden)] - // This is a temporary method for testing. NEVER use it in production - pub fn user_agent_for_tests(mut self) -> Self { - self.operation.properties_mut().insert(#{AwsUserAgent}::for_tests()); - self - } + headers.insert( + #{http}::HeaderName::from_static("x-amz-user-agent"), + #{http}::HeaderValue::try_from(user_agent.aws_ua_header()).unwrap(), + ); + }); + self.interceptors.push(#{SharedInterceptor}::new(interceptor)); + self + } - ##[doc(hidden)] - // This is a temporary method for testing. NEVER use it in production - pub fn remove_invocation_id_for_tests(self) -> Self { - self - } - """, - *codegenScope, - ) - } + ##[doc(hidden)] + // This is a temporary method for testing. NEVER use it in production + pub fn remove_invocation_id_for_tests(mut self) -> Self { + let interceptor = #{TestParamsSetterInterceptor}::new(|context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, _: &mut #{ConfigBag}| { + context.request_mut().headers_mut().remove("amz-sdk-invocation-id"); + }); + self.interceptors.push(#{SharedInterceptor}::new(interceptor)); + self + } + """, + *codegenScope, + ) } } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt index 21024e3a79..7b69c5c72a 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt @@ -12,7 +12,6 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.client.Fluen import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientDocs import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientSection -import software.amazon.smithy.rust.codegen.client.smithy.generators.client.NoClientGenerics import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.DefaultProtocolTestGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ProtocolTestGenerator import software.amazon.smithy.rust.codegen.core.rustlang.Attribute @@ -56,16 +55,13 @@ class AwsFluentClientDecorator : ClientCodegenDecorator { override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { val runtimeConfig = codegenContext.runtimeConfig val types = Types(runtimeConfig) - val generics = NoClientGenerics(runtimeConfig) FluentClientGenerator( codegenContext, reexportSmithyClientBuilder = false, - generics = generics, customizations = listOf( AwsPresignedFluentBuilderMethod(codegenContext), AwsFluentClientDocs(codegenContext), ), - retryClassifier = AwsRuntimeType.awsHttp(runtimeConfig).resolve("retry::AwsResponseRetryClassifier"), ).render(rustCrate, listOf(CustomizableOperationTestHelpers(runtimeConfig))) rustCrate.withModule(ClientRustModule.client) { AwsFluentClientExtensions(codegenContext, types).render(this) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt index 5c6f0ff91f..b8502f0d35 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt @@ -19,30 +19,22 @@ import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientSection -import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.MakeOperationGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.RequestSerializerGenerator -import software.amazon.smithy.rust.codegen.client.smithy.protocols.ClientHttpBoundProtocolPayloadGenerator import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.docs import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.withBlock import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope import software.amazon.smithy.rust.codegen.core.smithy.contextName import software.amazon.smithy.rust.codegen.core.util.cloneOperation import software.amazon.smithy.rust.codegen.core.util.expectTrait -import software.amazon.smithy.rust.codegen.core.util.hasTrait -import software.amazon.smithy.rustsdk.AwsRuntimeType.defaultMiddleware import software.amazon.smithy.rustsdk.traits.PresignableTrait import kotlin.streams.toList @@ -130,124 +122,6 @@ class AwsPresigningDecorator internal constructor( } } -// TODO(enableNewSmithyRuntimeCleanup): Delete this class when cleaning up middleware -class AwsInputPresignedMethod( - private val codegenContext: ClientCodegenContext, - private val operationShape: OperationShape, -) : OperationCustomization() { - private val runtimeConfig = codegenContext.runtimeConfig - private val symbolProvider = codegenContext.symbolProvider - - private val codegenScope = ( - presigningTypes + listOf( - "PresignedRequestService" to AwsRuntimeType.presigningService() - .resolve("PresignedRequestService"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - "aws_sigv4" to AwsRuntimeType.awsSigv4(runtimeConfig), - "sig_auth" to AwsRuntimeType.awsSigAuth(runtimeConfig), - "tower" to RuntimeType.Tower, - "Middleware" to runtimeConfig.defaultMiddleware(), - ) - ).toTypedArray() - - override fun section(section: OperationSection): Writable = - writable { - if (section is OperationSection.InputImpl && section.operationShape.hasTrait()) { - writeInputPresignedMethod(section) - } - } - - private fun RustWriter.writeInputPresignedMethod(section: OperationSection.InputImpl) { - val operationError = symbolProvider.symbolForOperationError(operationShape) - val presignableOp = PRESIGNABLE_OPERATIONS.getValue(operationShape.id) - - val makeOperationOp = if (presignableOp.hasModelTransforms()) { - codegenContext.model.expectShape(syntheticShapeId(operationShape.id), OperationShape::class.java) - } else { - section.operationShape - } - val makeOperationFn = "_make_presigned_operation" - - val protocol = section.protocol - MakeOperationGenerator( - codegenContext, - protocol, - ClientHttpBoundProtocolPayloadGenerator(codegenContext, protocol), - // Prefixed with underscore to avoid colliding with modeled functions - functionName = makeOperationFn, - public = false, - includeDefaultPayloadHeaders = false, - ).generateMakeOperation(this, makeOperationOp, section.customizations) - - documentPresignedMethod(hasConfigArg = true) - rustBlockTemplate( - """ - pub async fn presigned( - self, - config: &crate::config::Config, - presigning_config: #{PresigningConfig} - ) -> Result<#{PresignedRequest}, #{SdkError}<#{OpError}>> - """, - *codegenScope, - "OpError" to operationError, - ) { - rustTemplate( - """ - let (mut request, _) = self.$makeOperationFn(config) - .await - .map_err(#{SdkError}::construction_failure)? - .into_request_response(); - """, - *codegenScope, - ) - rustBlock("") { - rustTemplate( - """ - // Change signature type to query params and wire up presigning config - let mut props = request.properties_mut(); - props.insert(#{SharedTimeSource}::new(#{StaticTimeSource}::new(presigning_config.start_time()))); - """, - "SharedTimeSource" to RuntimeType.smithyAsync(runtimeConfig) - .resolve("time::SharedTimeSource"), - "StaticTimeSource" to RuntimeType.smithyAsync(runtimeConfig) - .resolve("time::StaticTimeSource"), - ) - withBlock("props.insert(", ");") { - rustTemplate( - "#{aws_sigv4}::http_request::SignableBody::" + - when (presignableOp.payloadSigningType) { - PayloadSigningType.EMPTY -> "Bytes(b\"\")" - PayloadSigningType.UNSIGNED_PAYLOAD -> "UnsignedPayload" - }, - *codegenScope, - ) - } - rustTemplate( - """ - let config = props.get_mut::<#{sig_auth}::signer::OperationSigningConfig>() - .expect("signing config added by make_operation()"); - config.signature_type = #{sig_auth}::signer::HttpSignatureType::HttpRequestQueryParams; - config.expires_in = Some(presigning_config.expires()); - """, - *codegenScope, - ) - } - rustTemplate( - """ - let middleware = #{Middleware}::default(); - let mut svc = #{tower}::builder::ServiceBuilder::new() - .layer(&middleware) - .service(#{PresignedRequestService}::new()); - - use #{tower}::{Service, ServiceExt}; - Ok(svc.ready().await?.call(request).await?) - """, - *codegenScope, - ) - } - } -} - class AwsPresignedFluentBuilderMethod( private val codegenContext: ClientCodegenContext, ) : FluentClientCustomization() { diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt index ec7e0ba3d0..47570de7f4 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt @@ -5,7 +5,6 @@ package software.amazon.smithy.rustsdk -import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig @@ -14,16 +13,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import java.io.File import java.nio.file.Path -fun defaultSdkVersion(): String { - // generated as part of the build, see codegen/build.gradle.kts - try { - return object {}.javaClass.getResource("sdk-crate-version.txt")?.readText() - ?: throw CodegenException("sdk-crate-version.txt does not exist") - } catch (ex: Exception) { - throw CodegenException("failed to load sdk-crate-version.txt which sets the default client-runtime version", ex) - } -} - fun RuntimeConfig.awsRoot(): RuntimeCrateLocation { val updatedPath = runtimeCrateLocation.path?.let { cratePath -> val asPath = Path.of(cratePath) @@ -53,10 +42,6 @@ object AwsRuntimeType { ), ) - // TODO(enableNewSmithyRuntimeCleanup): Delete the `presigning_service.rs` inlineable when cleaning up middleware - fun presigningService(): RuntimeType = - RuntimeType.forInlineDependency(InlineAwsDependency.forRustFile("presigning_service", visibility = Visibility.PUBCRATE)) - // TODO(enableNewSmithyRuntimeCleanup): Delete defaultMiddleware and middleware.rs, and remove tower dependency from inlinables, when cleaning up middleware fun RuntimeConfig.defaultMiddleware() = RuntimeType.forInlineDependency( InlineAwsDependency.forRustFile( @@ -78,9 +63,6 @@ object AwsRuntimeType { fun awsEndpoint(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsEndpoint(runtimeConfig).toType() fun awsHttp(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsHttp(runtimeConfig).toType() - fun awsSigAuth(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsSigAuth(runtimeConfig).toType() - fun awsSigAuthEventStream(runtimeConfig: RuntimeConfig) = - AwsCargoDependency.awsSigAuthEventStream(runtimeConfig).toType() fun awsSigv4(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsSigv4(runtimeConfig).toType() fun awsTypes(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsTypes(runtimeConfig).toType() diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialCaches.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialCaches.kt index 5188228b75..198d1b8bc4 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialCaches.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialCaches.kt @@ -5,18 +5,13 @@ package software.amazon.smithy.rustsdk -import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig -import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization @@ -25,6 +20,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.customize.adhocCustomizat class CredentialsCacheDecorator : ClientCodegenDecorator { override val name: String = "CredentialsCache" override val order: Byte = 0 + override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, @@ -32,14 +28,6 @@ class CredentialsCacheDecorator : ClientCodegenDecorator { return baseCustomizations + CredentialCacheConfig(codegenContext) } - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List { - return baseCustomizations + CredentialsCacheFeature(codegenContext.runtimeConfig) - } - override fun extraSections(codegenContext: ClientCodegenContext): List = listOf( adhocCustomization { section -> @@ -155,23 +143,3 @@ class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustom } } } - -class CredentialsCacheFeature(private val runtimeConfig: RuntimeConfig) : OperationCustomization() { - override fun section(section: OperationSection): Writable { - return when (section) { - is OperationSection.MutateRequest -> writable { - rust( - """ - #T(&mut ${section.request}.properties_mut(), ${section.config}.credentials_cache.clone()); - """, - setCredentialsCache(runtimeConfig), - ) - } - - else -> emptySection - } - } -} - -fun setCredentialsCache(runtimeConfig: RuntimeConfig) = - AwsRuntimeType.awsHttp(runtimeConfig).resolve("auth::set_credentials_cache") diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt index 610ad1c579..e5d105d4a7 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt @@ -40,20 +40,6 @@ private fun RuntimeConfig.awsInlineableHttpRequestChecksum() = RuntimeType.forIn ), ) -// TODO(enableNewSmithyRuntimeCleanup): Delete this method -fun RuntimeConfig.awsInlineableBodyWithChecksumMiddleware() = RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile( - "http_body_checksum_middleware", visibility = Visibility.PUBCRATE, - CargoDependency.Http, - CargoDependency.HttpBody, - CargoDependency.smithyHttp(this), - CargoDependency.smithyChecksums(this), - CargoDependency.smithyTypes(this), - CargoDependency.Bytes, - CargoDependency.Tracing, - ), -) - class HttpRequestChecksumDecorator : ClientCodegenDecorator { override val name: String = "HttpRequestChecksum" override val order: Byte = 0 @@ -80,8 +66,6 @@ private fun HttpChecksumTrait.requestAlgorithmMember( private fun HttpChecksumTrait.checksumAlgorithmToStr( codegenContext: ClientCodegenContext, operationShape: OperationShape, - // TODO(enableNewSmithyRuntimeCleanup): Remove `algorithmWasCloned` (it should always be false) - algorithmWasCloned: Boolean, ): Writable { val runtimeConfig = codegenContext.runtimeConfig val requestAlgorithmMember = this.requestAlgorithmMember(codegenContext, operationShape) @@ -89,11 +73,6 @@ private fun HttpChecksumTrait.checksumAlgorithmToStr( return { if (requestAlgorithmMember != null) { - if (algorithmWasCloned) { - // User may set checksum for requests, and we need to call as_ref before we can convert the algorithm to a &str - rust("let checksum_algorithm = $requestAlgorithmMember.as_ref();") - } - if (isRequestChecksumRequired) { // Checksums are required, fall back to MD5 rust("""let checksum_algorithm = checksum_algorithm.map(|algorithm| algorithm.as_str()).or(Some("md5"));""") @@ -162,46 +141,11 @@ class HttpRequestChecksumCustomization( "checksum_algorithm_to_str" to checksumTrait.checksumAlgorithmToStr( codegenContext, operationShape, - algorithmWasCloned = false, ), ) } } } - // TODO(enableNewSmithyRuntimeCleanup): Delete `is OperationSection.MutateInput` - is OperationSection.MutateInput -> { - // Various other things will consume the input struct before we can get at the checksum algorithm - // field within it. This ensures that we preserve a copy of it. It's an enum so cloning is cheap. - if (requestAlgorithmMember != null) { - rust("let $requestAlgorithmMember = self.$requestAlgorithmMember().cloned();") - } - } - // TODO(enableNewSmithyRuntimeCleanup): Delete `is OperationSection.MutateRequest` - is OperationSection.MutateRequest -> { - // Return early if no request checksum can be set nor is it required - if (checksumTrait.isRequestChecksumRequired || requestAlgorithmMember != null) { - // `add_checksum_calculation_to_request` handles both streaming and in-memory request bodies. - rustTemplate( - """ - ${section.request} = ${section.request}.augment(|mut req, properties| { - #{checksum_algorithm_to_str:W} - if let Some(checksum_algorithm) = checksum_algorithm { - #{add_checksum_calculation_to_request}(&mut req, properties, checksum_algorithm)?; - } - Result::<_, #{BuildError}>::Ok(req) - })?; - """, - "checksum_algorithm_to_str" to checksumTrait.checksumAlgorithmToStr( - codegenContext, - operationShape, - algorithmWasCloned = true, - ), - "add_checksum_calculation_to_request" to runtimeConfig.awsInlineableBodyWithChecksumMiddleware() - .resolve("add_checksum_calculation_to_request"), - "BuildError" to runtimeConfig.operationBuildError(), - ) - } - } else -> { } } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt index 114644daaf..5b35198f8a 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt @@ -113,66 +113,6 @@ class HttpResponseChecksumCustomization( ) } } - // TODO(enableNewSmithyRuntimeCleanup): Delete `is OperationSection.MutateRequest` - is OperationSection.MutateRequest -> { - // Otherwise, we need to set a property that the `MutateOutput` section handler will read to know if it - // should checksum validate the response. - rustTemplate( - """ - if let Some($validationModeName) = self.$validationModeName.as_ref() { - let $validationModeName = $validationModeName.clone(); - // Place #{ValidationModeShape} in the property bag so we can check - // it during response deserialization to see if we need to checksum validate - // the response body. - let _ = request.properties_mut().insert($validationModeName); - } - """, - "ValidationModeShape" to codegenContext.symbolProvider.toSymbol(requestValidationModeMemberInner), - ) - } - // TODO(enableNewSmithyRuntimeCleanup): Delete `is OperationSection.MutateOutput` - is OperationSection.MutateOutput -> { - if (!section.propertyBagAvailable) { - return@writable - } - - // CRC32, CRC32C, SHA256, SHA1 -> "crc32", "crc32c", "sha256", "sha1" - val responseAlgorithms = checksumTrait.responseAlgorithms - .map { algorithm -> algorithm.lowercase() }.joinToString(", ") { algorithm -> "\"$algorithm\"" } - - rustTemplate( - """ - let response_algorithms = [$responseAlgorithms].as_slice(); - let $validationModeName = properties.get::<#{ValidationModeShape}>(); - // Per [the spec](https://smithy.io/2.0/aws/aws-core.html##http-response-checksums), - // we check to see if it's the `ENABLED` variant - if matches!($validationModeName, Some(&#{ValidationModeShape}::Enabled)) { - if let Some((checksum_algorithm, precalculated_checksum)) = - #{check_headers_for_precalculated_checksum}( - response.headers(), - response_algorithms, - ) - { - let bytestream = output.body.take().map(|bytestream| { - bytestream.map(move |sdk_body| { - #{wrap_body_with_checksum_validator}( - sdk_body, - checksum_algorithm, - precalculated_checksum.clone(), - ) - }) - }); - output = output.set_body(bytestream); - } - } - """, - "ValidationModeShape" to codegenContext.symbolProvider.toSymbol(requestValidationModeMemberInner), - "wrap_body_with_checksum_validator" to codegenContext.runtimeConfig.awsInlineableBodyWithChecksumMiddleware() - .resolve("wrap_body_with_checksum_validator"), - "check_headers_for_precalculated_checksum" to codegenContext.runtimeConfig.awsInlineableBodyWithChecksumMiddleware() - .resolve("check_headers_for_precalculated_checksum"), - ) - } else -> {} } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt index d8a5fc7052..804e4ec3c3 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt @@ -6,15 +6,12 @@ package software.amazon.smithy.rustsdk import software.amazon.smithy.model.node.Node -import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rulesengine.language.syntax.parameters.Builtins import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -93,14 +90,6 @@ class RegionDecorator : ClientCodegenDecorator { } } - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List { - return baseCustomizations.extendIf(usesRegion(codegenContext)) { RegionConfigPlugin() } - } - override fun extraSections(codegenContext: ClientCodegenContext): List { return usesRegion(codegenContext).thenSingletonListOf { adhocCustomization { section -> @@ -216,23 +205,4 @@ class RegionProviderConfig(codegenContext: ClientCodegenContext) : ConfigCustomi } } -class RegionConfigPlugin : OperationCustomization() { - override fun section(section: OperationSection): Writable { - return when (section) { - is OperationSection.MutateRequest -> writable { - // Allow the region to be late-inserted via another method - rust( - """ - if let Some(region) = &${section.config}.region { - ${section.request}.properties_mut().insert(region.clone()); - } - """, - ) - } - - else -> emptySection - } - } -} - fun region(runtimeConfig: RuntimeConfig) = AwsRuntimeType.awsTypes(runtimeConfig).resolve("region") diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt index e60fe98615..12fec39968 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt @@ -10,10 +10,8 @@ import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType class RetryClassifierDecorator : ClientCodegenDecorator { @@ -25,26 +23,9 @@ class RetryClassifierDecorator : ClientCodegenDecorator { operation: OperationShape, baseCustomizations: List, ): List = baseCustomizations + - RetryClassifierFeature(codegenContext.runtimeConfig) + OperationRetryClassifiersFeature(codegenContext, operation) } -class RetryClassifierFeature(private val runtimeConfig: RuntimeConfig) : OperationCustomization() { - override fun retryType(): RuntimeType = - AwsRuntimeType.awsHttp(runtimeConfig).resolve("retry::AwsResponseRetryClassifier") - - override fun section(section: OperationSection) = when (section) { - is OperationSection.FinalizeOperation -> writable { - rust( - "let ${section.operation} = ${section.operation}.with_retry_classifier(#T::new());", - retryType(), - ) - } - - else -> emptySection - } -} - class OperationRetryClassifiersFeature( codegenContext: ClientCodegenContext, operation: OperationShape, diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index 5f92d6ee1c..90b6fd3ce5 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -9,6 +9,8 @@ import software.amazon.smithy.aws.traits.auth.SigV4Trait import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait import software.amazon.smithy.model.knowledge.ServiceIndex import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator @@ -16,11 +18,16 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCus import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection +import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.util.dq +import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.hasEventStreamOperations import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.isInputEventStream @@ -52,6 +59,55 @@ class SigV4AuthDecorator : ClientCodegenDecorator { operation: OperationShape, baseCustomizations: List, ): List = baseCustomizations + AuthOperationCustomization(codegenContext) + + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations + SigV4SigningConfig(codegenContext.runtimeConfig, codegenContext.serviceShape.getTrait()) +} + +private class SigV4SigningConfig( + runtimeConfig: RuntimeConfig, + private val sigV4Trait: SigV4Trait?, +) : ConfigCustomization() { + private val codegenScope = arrayOf( + "Region" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::Region"), + "SigningName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningName"), + "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), + ) + + override fun section(section: ServiceConfig): Writable = writable { + if (sigV4Trait != null) { + when (section) { + ServiceConfig.ConfigImpl -> { + rust( + """ + /// The signature version 4 service signing name to use in the credential scope when signing requests. + /// + /// The signing service may be overridden by the `Endpoint`, or by specifying a custom + /// [`SigningName`](aws_types::SigningName) during operation construction + pub fn signing_name(&self) -> &'static str { + ${sigV4Trait.name.dq()} + } + """, + ) + } + + ServiceConfig.BuilderBuild -> { + rustTemplate( + """ + layer.store_put(#{SigningName}::from_static(${sigV4Trait.name.dq()})); + layer.load::<#{Region}>().cloned().map(|r| layer.store_put(#{SigningRegion}::from(r))); + """, + *codegenScope, + ) + } + + else -> {} + } + } + } } private class AuthServiceRuntimePluginCustomization(private val codegenContext: ClientCodegenContext) : @@ -83,6 +139,22 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: } } +private fun needsAmzSha256(service: ServiceShape) = when (service.id) { + ShapeId.from("com.amazonaws.s3#AmazonS3") -> true + ShapeId.from("com.amazonaws.s3control#AWSS3ControlServiceV20180820") -> true + else -> false +} + +private fun disableDoubleEncode(service: ServiceShape) = when (service.id) { + ShapeId.from("com.amazonaws.s3#AmazonS3") -> true + else -> false +} + +private fun disableUriPathNormalization(service: ServiceShape) = when (service.id) { + ShapeId.from("com.amazonaws.s3#AmazonS3") -> true + else -> false +} + private class AuthOperationCustomization(private val codegenContext: ClientCodegenContext) : OperationCustomization() { private val runtimeConfig = codegenContext.runtimeConfig private val codegenScope by lazy { diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt deleted file mode 100644 index e79044c797..0000000000 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rustsdk - -import software.amazon.smithy.aws.traits.auth.SigV4Trait -import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.knowledge.ServiceIndex -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.ShapeId -import software.amazon.smithy.model.traits.OptionalAuthTrait -import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig -import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.core.util.expectTrait -import software.amazon.smithy.rust.codegen.core.util.extendIf -import software.amazon.smithy.rust.codegen.core.util.hasEventStreamOperations -import software.amazon.smithy.rust.codegen.core.util.hasTrait -import software.amazon.smithy.rust.codegen.core.util.isInputEventStream - -// TODO(enableNewSmithyRuntimeCleanup): Remove this decorator (superseded by SigV4AuthDecorator) -/** - * The SigV4SigningDecorator: - * - adds a `name()` method to `config` to return the default signing service - * - adds a `new_event_stream_signer()` method to `config` to create an Event Stream SigV4 signer - * - sets the `SigningName` during operation construction - * - sets a default `OperationSigningConfig` A future enhancement will customize this for specific services that need - * different behavior. - */ -class SigV4SigningDecorator : ClientCodegenDecorator { - override val name: String = "SigV4Signing" - override val order: Byte = 0 - - private fun applies(codegenContext: CodegenContext): Boolean = codegenContext.serviceShape.hasTrait() - - override fun configCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List { - return baseCustomizations.extendIf(applies(codegenContext)) { - SigV4SigningConfig( - codegenContext.runtimeConfig, - codegenContext.serviceShape.hasEventStreamOperations(codegenContext.model), - codegenContext.serviceShape.expectTrait(), - ) - } - } - - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List { - return baseCustomizations.extendIf(applies(codegenContext)) { - SigV4SigningFeature( - codegenContext.model, - operation, - codegenContext.runtimeConfig, - codegenContext.serviceShape, - ) - } - } -} - -class SigV4SigningConfig( - private val runtimeConfig: RuntimeConfig, - private val serviceHasEventStream: Boolean, - private val sigV4Trait: SigV4Trait, -) : ConfigCustomization() { - private val codegenScope = arrayOf( - "Region" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::Region"), - "SigningName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningName"), - "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), - ) - - override fun section(section: ServiceConfig): Writable = writable { - when (section) { - ServiceConfig.ConfigImpl -> { - rust( - """ - /// The signature version 4 service signing name to use in the credential scope when signing requests. - /// - /// The signing name may be overridden by the `Endpoint`, or by specifying a custom - /// [`SigningName`](aws_types::SigningName) during operation construction - pub fn name(&self) -> &'static str { - ${sigV4Trait.name.dq()} - } - """, - ) - } - ServiceConfig.BuilderBuild -> { - rustTemplate( - """ - layer.store_put(#{SigningName}::from_static(${sigV4Trait.name.dq()})); - layer.load::<#{Region}>().cloned().map(|r| layer.store_put(#{SigningRegion}::from(r))); - """, - *codegenScope, - ) - } - - else -> emptySection - } - } -} - -fun needsAmzSha256(service: ServiceShape) = when (service.id) { - ShapeId.from("com.amazonaws.s3#AmazonS3") -> true - ShapeId.from("com.amazonaws.s3control#AWSS3ControlServiceV20180820") -> true - else -> false -} - -fun disableDoubleEncode(service: ServiceShape) = when (service.id) { - ShapeId.from("com.amazonaws.s3#AmazonS3") -> true - else -> false -} - -fun disableUriPathNormalization(service: ServiceShape) = when (service.id) { - ShapeId.from("com.amazonaws.s3#AmazonS3") -> true - else -> false -} - -class SigV4SigningFeature( - private val model: Model, - private val operation: OperationShape, - runtimeConfig: RuntimeConfig, - private val service: ServiceShape, -) : - OperationCustomization() { - private val codegenScope = arrayOf( - "sig_auth" to AwsRuntimeType.awsSigAuth(runtimeConfig), - "aws_types" to AwsRuntimeType.awsTypes(runtimeConfig), - ) - - private val serviceIndex = ServiceIndex.of(model) - - override fun section(section: OperationSection): Writable { - return when (section) { - is OperationSection.MutateRequest -> writable { - rustTemplate( - "let mut signing_config = #{sig_auth}::signer::OperationSigningConfig::default_config();", - *codegenScope, - ) - if (needsAmzSha256(service)) { - rust("signing_config.signing_options.content_sha256_header = true;") - } - if (disableDoubleEncode(service)) { - rust("signing_config.signing_options.double_uri_encode = false;") - } - if (disableUriPathNormalization(service)) { - rust("signing_config.signing_options.normalize_uri_path = false;") - } - if (operation.hasTrait()) { - rust("signing_config.signing_options.content_sha256_header = true;") - rustTemplate( - "${section.request}.properties_mut().insert(#{sig_auth}::signer::SignableBody::UnsignedPayload);", - *codegenScope, - ) - } else if (operation.isInputEventStream(model)) { - // TODO(EventStream): Is this actually correct for all Event Stream operations? - rustTemplate( - "${section.request}.properties_mut().insert(#{sig_auth}::signer::SignableBody::Bytes(&[]));", - *codegenScope, - ) - } - // some operations are either unsigned or optionally signed: - val authSchemes = serviceIndex.getEffectiveAuthSchemes(service, operation) - if (!authSchemes.containsKey(SigV4Trait.ID)) { - rustTemplate( - "signing_config.signing_requirements = #{sig_auth}::signer::SigningRequirements::Disabled;", - *codegenScope, - ) - } else { - if (operation.hasTrait()) { - rustTemplate( - "signing_config.signing_requirements = #{sig_auth}::signer::SigningRequirements::Optional;", - *codegenScope, - ) - } - } - rustTemplate( - """ - ${section.request}.properties_mut().insert(signing_config); - ${section.request}.properties_mut().insert(#{aws_types}::SigningName::from_static(${section.config}.name())); - if let Some(region) = &${section.config}.region { - ${section.request}.properties_mut().insert(#{aws_types}::region::SigningRegion::from(region.clone())); - } - """, - *codegenScope, - ) - } - - else -> emptySection - } - } -} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt index a5f2c7003f..5d1ee8cb91 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt @@ -6,12 +6,9 @@ package software.amazon.smithy.rustsdk import software.amazon.smithy.aws.traits.ServiceTrait -import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization @@ -42,14 +39,6 @@ class UserAgentDecorator : ClientCodegenDecorator { return baseCustomizations + AppNameCustomization(codegenContext) } - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List { - return baseCustomizations + UserAgentMutateOpRequest(codegenContext) - } - override fun serviceRuntimePluginCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, @@ -111,35 +100,6 @@ class UserAgentDecorator : ClientCodegenDecorator { } } - // TODO(enableNewSmithyRuntimeCleanup): Remove this customization class - private class UserAgentMutateOpRequest( - codegenContext: ClientCodegenContext, - ) : OperationCustomization() { - private val runtimeConfig = codegenContext.runtimeConfig - - override fun section(section: OperationSection): Writable = when (section) { - is OperationSection.MutateRequest -> writable { - rustTemplate( - """ - let mut user_agent = #{ua_module}::AwsUserAgent::new_from_environment( - #{Env}::real(), - #{meta}::API_METADATA.clone(), - ); - if let Some(app_name) = _config.app_name() { - user_agent = user_agent.with_app_name(app_name.clone()); - } - ${section.request}.properties_mut().insert(user_agent); - """, - "meta" to ClientRustModule.Meta, - "ua_module" to AwsRuntimeType.awsHttp(runtimeConfig).resolve("user_agent"), - "Env" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("os_shim_internal::Env"), - ) - } - - else -> emptySection - } - } - private class AppNameCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() { private val runtimeConfig = codegenContext.runtimeConfig private val codegenScope = arrayOf( diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/AccountIdAutofill.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/AccountIdAutofill.kt deleted file mode 100644 index 6b18ca9116..0000000000 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/AccountIdAutofill.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rustsdk.customize.glacier - -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.util.inputShape - -// TODO(enableNewSmithyRuntimeCleanup): Delete this file when cleaning up middleware. - -class AccountIdAutofill : OperationCustomization() { - override fun mutSelf(): Boolean = true - override fun consumesSelf(): Boolean = false - override fun section(section: OperationSection): Writable { - return when (section) { - is OperationSection.MutateInput -> writable { - rust( - """ - if ${section.input}.account_id.as_deref().unwrap_or_default().is_empty() { - ${section.input}.account_id = Some("-".to_owned()); - } - """, - ) - } - else -> emptySection - } - } - - companion object { - fun forOperation(operation: OperationShape, model: Model): AccountIdAutofill? { - val input = operation.inputShape(model) - return if (input.memberNames.contains("accountId")) { - AccountIdAutofill() - } else { - null - } - } - } -} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/ApiVersionHeader.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/ApiVersionHeader.kt deleted file mode 100644 index 093bd61061..0000000000 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/ApiVersionHeader.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rustsdk.customize.glacier - -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.util.dq - -// TODO(enableNewSmithyRuntimeCleanup): Delete this file when cleaning up middleware. - -class ApiVersionHeader( - /** - * ApiVersion - * This usually comes from the `version` field of the service shape and is usually a date like "2012-06-01" - * */ - private val apiVersion: String, -) : OperationCustomization() { - override fun section(section: OperationSection): Writable = when (section) { - is OperationSection.FinalizeOperation -> emptySection - is OperationSection.OperationImplBlock -> emptySection - is OperationSection.MutateRequest -> writable { - rust( - """${section.request} - .http_mut() - .headers_mut() - .insert("x-amz-glacier-version", #T::HeaderValue::from_static(${apiVersion.dq()}));""", - RuntimeType.Http, - ) - } - else -> emptySection - } -} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/TreeHashHeader.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/TreeHashHeader.kt deleted file mode 100644 index ff03c29dda..0000000000 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/TreeHashHeader.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rustsdk.customize.glacier - -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ShapeId -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.generators.operationBuildError -import software.amazon.smithy.rustsdk.InlineAwsDependency - -// TODO(enableNewSmithyRuntimeCleanup): Delete this file when cleaning up middleware. - -val TreeHashDependencies = listOf( - CargoDependency.Ring, - CargoDependency.TokioStream, - CargoDependency.BytesUtils, - CargoDependency.Bytes, - CargoDependency.Tokio, - CargoDependency.Hex, - CargoDependency.TempFile, -) - -private val UploadArchive: ShapeId = ShapeId.from("com.amazonaws.glacier#UploadArchive") -private val UploadMultipartPart: ShapeId = ShapeId.from("com.amazonaws.glacier#UploadMultipartPart") -private val Applies = setOf(UploadArchive, UploadMultipartPart) - -class TreeHashHeader(private val runtimeConfig: RuntimeConfig) : OperationCustomization() { - private val glacierChecksums = RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile( - "glacier_checksums", - additionalDependency = TreeHashDependencies.toTypedArray(), - ), - ) - - override fun section(section: OperationSection): Writable { - return when (section) { - is OperationSection.MutateRequest -> writable { - rustTemplate( - """ - #{glacier_checksums}::add_checksum_treehash( - &mut ${section.request} - ).await.map_err(#{BuildError}::other)?; - """, - "glacier_checksums" to glacierChecksums, "BuildError" to runtimeConfig.operationBuildError(), - ) - } - - else -> emptySection - } - } - - companion object { - fun forOperation(operation: OperationShape, runtimeConfig: RuntimeConfig): TreeHashHeader? { - return if (Applies.contains(operation.id)) { - TreeHashHeader(runtimeConfig) - } else { - null - } - } - } -} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt index 9e0888fa39..bf1b386249 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt @@ -69,26 +69,10 @@ class TrimResourceIdCustomization( private val codegenContext: ClientCodegenContext, private val inputShape: StructureShape, private val fieldName: String, -) : - OperationCustomization() { - override fun mutSelf(): Boolean = true - override fun consumesSelf(): Boolean = true +) : OperationCustomization() { override fun section(section: OperationSection): Writable = writable { when (section) { - // TODO(enableNewSmithyRuntimeCleanup): Delete this `MutateInput` section - is OperationSection.MutateInput -> { - val trimResourceId = - RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile("route53_resource_id_preprocessor_middleware"), - ) - .resolve("trim_resource_id") - rustTemplate( - "#{trim_resource_id}(&mut ${section.input}.$fieldName);", - "trim_resource_id" to trimResourceId, - ) - } - is OperationSection.AdditionalInterceptors -> { section.registerInterceptor(codegenContext.runtimeConfig, this) { val smithyRuntimeApi = RuntimeType.smithyRuntimeApi(codegenContext.runtimeConfig) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt index d274c5b183..503d8ae4f3 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt @@ -61,7 +61,7 @@ class TimestreamDecorator : ClientCodegenDecorator { #{ResolveEndpointError}::from_source("failed to call describe_endpoints", e) })?; let endpoint = describe_endpoints.endpoints().unwrap().get(0).unwrap(); - let expiry = client.conf().time_source().expect("checked when ep discovery was enabled").now() + let expiry = client.config().time_source().expect("checked when ep discovery was enabled").now() + #{Duration}::from_secs(endpoint.cache_period_in_minutes() as u64 * 60); Ok(( #{Endpoint}::builder() diff --git a/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt b/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt index 02ae9071d3..da4f719625 100644 --- a/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt @@ -48,17 +48,6 @@ class SdkCodegenIntegrationTest { @Test fun smokeTestSdkCodegen() { - awsSdkIntegrationTest( - model, - generateOrchestrator = true, - ) { _, _ -> /* it should compile */ } - } - - @Test - fun smokeTestSdkCodegenMiddleware() { - awsSdkIntegrationTest( - model, - generateOrchestrator = false, - ) { _, _ -> /* it should compile */ } + awsSdkIntegrationTest(model) { _, _ -> /* it should compile */ } } } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialCacheConfigTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialCacheConfigTest.kt index 960d3adbaf..699e425d87 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialCacheConfigTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialCacheConfigTest.kt @@ -48,7 +48,7 @@ internal class CredentialCacheConfigTest { @Test fun `config override for credentials`() { - awsSdkIntegrationTest(model, generateOrchestrator = true) { clientCodegenContext, rustCrate -> + awsSdkIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig val codegenScope = arrayOf( *RuntimeType.preludeScope, diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt deleted file mode 100644 index da7df57765..0000000000 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rustsdk - -import org.junit.jupiter.api.Test -import software.amazon.smithy.aws.traits.auth.SigV4Trait -import software.amazon.smithy.rust.codegen.client.testutil.stubConfigProject -import software.amazon.smithy.rust.codegen.client.testutil.testClientRustSettings -import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace -import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest -import software.amazon.smithy.rust.codegen.core.testutil.unitTest - -internal class SigV4SigningDecoratorTest { - @Test - fun `generates a valid config`() { - val codegenContext = awsTestCodegenContext( - settings = testClientRustSettings( - runtimeConfig = AwsTestRuntimeConfig, - ), - ) - val project = stubConfigProject( - codegenContext, - SigV4SigningConfig( - codegenContext.runtimeConfig, - true, - SigV4Trait.builder().name("test-service").build(), - ), - TestWorkspace.testProject(), - ) - project.lib { - unitTest( - "signing_name_override", - """ - let conf = crate::config::Config::builder().build(); - assert_eq!(conf.name(), "test-service"); - """, - ) - } - project.compileAndTest() - } -} diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt index 44ed5461a9..34905620b8 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt @@ -7,7 +7,6 @@ package software.amazon.smithy.rustsdk import software.amazon.smithy.model.Model import software.amazon.smithy.model.node.ObjectNode -import software.amazon.smithy.model.node.StringNode import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest @@ -18,7 +17,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel -import software.amazon.smithy.rust.codegen.core.util.letIf import java.io.File // In aws-sdk-codegen, the working dir when gradle runs tests is actually `./aws`. So, to find the smithy runtime, we need @@ -37,10 +35,8 @@ fun awsTestCodegenContext(model: Model? = null, settings: ClientRustSettings? = settings = settings ?: testClientRustSettings(runtimeConfig = AwsTestRuntimeConfig), ) -// TODO(enableNewSmithyRuntimeCleanup): Remove generateOrchestrator once the runtime switches to the orchestrator fun awsSdkIntegrationTest( model: Model, - generateOrchestrator: Boolean = true, test: (ClientCodegenContext, RustCrate) -> Unit = { _, _ -> }, ) = clientIntegrationTest( @@ -63,9 +59,6 @@ fun awsSdkIntegrationTest( "codegen", ObjectNode.builder() .withMember("includeFluentClient", false) - .letIf(generateOrchestrator) { - it.withMember("enableNewSmithyRuntime", StringNode.from("orchestrator")) - } .build(), ).build(), ), diff --git a/aws/sdk/integration-tests/webassembly/src/default_config.rs b/aws/sdk/integration-tests/webassembly/src/default_config.rs index fd8899cbe0..181d1bb470 100644 --- a/aws/sdk/integration-tests/webassembly/src/default_config.rs +++ b/aws/sdk/integration-tests/webassembly/src/default_config.rs @@ -29,5 +29,5 @@ pub(crate) fn get_default_config() -> impl Future - EndpointTraitBindings( - codegenContext.model, - codegenContext.symbolProvider, - codegenContext.runtimeConfig, - shape, - epTrait, - ) - }.orNull() - } - - override fun section(section: OperationSection): Writable = when (section) { - is OperationSection.MutateRequest -> writable { - endpointTraitBindings(codegenContext, shape)?.also { endpointTraitBindings -> - withBlock("let endpoint_prefix = ", "?;") { - endpointTraitBindings.render(this, "self") - } - rust("request.properties_mut().insert(endpoint_prefix);") - } - } - - else -> emptySection - } -} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt index e654b48421..94c37d0d73 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt @@ -19,8 +19,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.toType import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.generators.operationBuildError import software.amazon.smithy.rust.codegen.core.util.hasStreamingMember import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.inputShape @@ -53,28 +51,6 @@ class HttpChecksumRequiredGenerator( ) } } - is OperationSection.MutateRequest -> writable { - rustTemplate( - """ - ${section.request} = ${section.request}.augment(|mut req, _| { - let data = req - .body() - .bytes() - .expect("checksum can only be computed for non-streaming operations"); - let checksum = <#{md5}::Md5 as #{md5}::Digest>::digest(data); - req.headers_mut().insert( - #{http}::header::HeaderName::from_static("content-md5"), - #{base64_encode}(&checksum[..]).parse().expect("checksum is valid header value") - ); - Result::<_, #{BuildError}>::Ok(req) - })?; - """, - "md5" to RuntimeType.Md5, - "http" to RuntimeType.Http, - "base64_encode" to RuntimeType.base64Encode(codegenContext.runtimeConfig), - "BuildError" to codegenContext.runtimeConfig.operationBuildError(), - ) - } else -> emptySection } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpVersionListCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpVersionListCustomization.kt deleted file mode 100644 index 43dab5ba8c..0000000000 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpVersionListCustomization.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.client.smithy.customizations - -import software.amazon.smithy.aws.traits.protocols.AwsProtocolTrait -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.util.getTrait -import software.amazon.smithy.rust.codegen.core.util.isEventStream - -// TODO(enableNewSmithyRuntimeCleanup): Delete this file - -class HttpVersionListCustomization( - private val codegenContext: CodegenContext, - private val operationShape: OperationShape, -) : OperationCustomization() { - override fun section(section: OperationSection): Writable { - val runtimeConfig = codegenContext.runtimeConfig - val awsProtocolTrait = codegenContext.serviceShape.getTrait() - val supportedHttpProtocolVersions = if (awsProtocolTrait == null) { - // No protocol trait was defined, use default http versions - "#{defaultHttpVersions}.clone()" - } else { - // Figure out whether we're dealing with an EventStream operation and fetch the corresponding list of desired HTTP versions - val versionList = if (operationShape.isEventStream(codegenContext.model)) awsProtocolTrait.eventStreamHttp else awsProtocolTrait.http - if (versionList.isEmpty()) { - // If no desired versions are specified, go with the default - "#{defaultHttpVersions}.clone()" - } else { - // otherwise, use the specified versions - "vec![${versionList.joinToString(",") { version -> mapHttpVersion(version) }}]" - } - } - - return when (section) { - is OperationSection.MutateRequest -> writable { - rustTemplate( - """ - ${section.request}.properties_mut().insert($supportedHttpProtocolVersions); - """, - "defaultHttpVersions" to RuntimeType.smithyHttp(runtimeConfig).resolve("http_versions::DEFAULT_HTTP_VERSION_LIST"), - ) - } - else -> emptySection - } - } -} - -// Map an ALPN protocol ID to a version from the `http` Rust crate -private fun mapHttpVersion(httpVersion: String): String { - return when (httpVersion) { - "http/1.1" -> "http::Version::HTTP_11" - "h2" -> "http::Version::HTTP_2" - else -> TODO("Unsupported HTTP version '$httpVersion', please check your model") - } -} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt index 3ee06bcea5..eead91bbe0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt @@ -61,20 +61,7 @@ class IdempotencyTokenGenerator( ) } } - is OperationSection.MutateInput -> writable { - rustTemplate( - """ - if ${section.input}.$memberName.is_none() { - ${section.input}.$memberName = #{Some}(${section.config}.idempotency_token_provider.make_idempotency_token()); - } - """, - *preludeScope, - ) - } else -> emptySection } } - - override fun consumesSelf(): Boolean = idempotencyTokenMember != null - override fun mutSelf(): Boolean = idempotencyTokenMember != null } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt index 216779ca26..f3402c950d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt @@ -6,11 +6,8 @@ package software.amazon.smithy.rust.codegen.client.smithy.customizations import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig -import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate @@ -100,19 +97,3 @@ class TimeSourceCustomization(codegenContext: ClientCodegenContext) : ConfigCust } } } - -class TimeSourceOperationCustomization : OperationCustomization() { - override fun section(section: OperationSection): Writable { - return when (section) { - is OperationSection.MutateRequest -> writable { - rust( - """ - ${section.request}.properties_mut().insert(${section.config}.time_source.clone()); - """, - ) - } - - else -> emptySection - } - } -} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt index 88858a652e..80347a2425 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/RequiredCustomizations.kt @@ -9,9 +9,7 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.customizations.ConnectionPoisoningRuntimePluginCustomization -import software.amazon.smithy.rust.codegen.client.smithy.customizations.EndpointPrefixGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpChecksumRequiredGenerator -import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpVersionListCustomization import software.amazon.smithy.rust.codegen.client.smithy.customizations.IdempotencyTokenGenerator import software.amazon.smithy.rust.codegen.client.smithy.customizations.InterceptorConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.customizations.MetadataCustomization @@ -19,7 +17,6 @@ import software.amazon.smithy.rust.codegen.client.smithy.customizations.Resilien import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyReExportCustomization import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyServiceRuntimePluginCustomization import software.amazon.smithy.rust.codegen.client.smithy.customizations.TimeSourceCustomization -import software.amazon.smithy.rust.codegen.client.smithy.customizations.TimeSourceOperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization @@ -50,10 +47,7 @@ class RequiredCustomizations : ClientCodegenDecorator { baseCustomizations + MetadataCustomization(codegenContext, operation) + IdempotencyTokenGenerator(codegenContext, operation) + - EndpointPrefixGenerator(codegenContext, operation) + - HttpChecksumRequiredGenerator(codegenContext, operation) + - HttpVersionListCustomization(codegenContext, operation) + - TimeSourceOperationCustomization() + HttpChecksumRequiredGenerator(codegenContext, operation) override fun configCustomizations( codegenContext: ClientCodegenContext, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt index ba197e35f1..56ab765606 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt @@ -5,33 +5,17 @@ package software.amazon.smithy.rust.codegen.client.smithy.endpoint -import software.amazon.smithy.model.node.BooleanNode import software.amazon.smithy.model.node.Node -import software.amazon.smithy.model.node.StringNode -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ShapeType import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter -import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters -import software.amazon.smithy.rulesengine.traits.ContextIndex import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.CustomRuntimeFunction -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointParamsGenerator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.endpointTestsModule import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rulesgen.SmithyEndpointsStdLib -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RustCrate -import software.amazon.smithy.rust.codegen.core.util.PANIC -import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.core.util.orNull /** * BuiltInResolver enables potentially external codegen stages to provide sources for `builtIn` parameters. @@ -102,18 +86,6 @@ class EndpointsDecorator : ClientCodegenDecorator { override val name: String = "Endpoints" override val order: Byte = 0 - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List { - return baseCustomizations + InjectEndpointInMakeOperation( - codegenContext, - EndpointTypesGenerator.fromContext(codegenContext), - operation, - ) - } - override fun endpointCustomizations(codegenContext: ClientCodegenContext): List { return listOf( object : EndpointCustomization { @@ -140,109 +112,4 @@ class EndpointsDecorator : ClientCodegenDecorator { } } } - - /** - * Creates an `::endpoint_resolver::Params` structure in make operation generator. This combines state from the - * client, the operation, and the model to create parameters. - * - * Example generated code: - * ```rust - * let _endpoint_params = crate::endpoint_resolver::Params::builder() - * .set_region(Some("test-region")) - * .set_disable_everything(Some(true)) - * .set_bucket(input.bucket.as_ref()) - * .build(); - * ``` - */ - // TODO(enableNewSmithyRuntimeCleanup): Delete this customization - class InjectEndpointInMakeOperation( - private val ctx: ClientCodegenContext, - private val typesGenerator: EndpointTypesGenerator, - private val operationShape: OperationShape, - ) : - OperationCustomization() { - - private val idx = ContextIndex.of(ctx.model) - private val types = Types(ctx.runtimeConfig) - - override fun section(section: OperationSection): Writable { - val codegenScope = arrayOf( - *RuntimeType.preludeScope, - "Params" to typesGenerator.paramsStruct(), - "ResolveEndpoint" to types.resolveEndpoint, - "ResolveEndpointError" to types.resolveEndpointError, - ) - return when (section) { - is OperationSection.MutateInput -> writable { - rustTemplate( - """ - use #{ResolveEndpoint}; - let params_result = #{Params}::builder()#{builderFields:W}.build() - .map_err(|err| #{ResolveEndpointError}::from_source("could not construct endpoint parameters", err)); - let (endpoint_result, params) = match params_result { - #{Ok}(params) => (${section.config}.endpoint_resolver.resolve_endpoint(¶ms), #{Some}(params)), - #{Err}(e) => (#{Err}(e), #{None}) - }; - """, - "builderFields" to builderFields(typesGenerator.params, section), - *codegenScope, - ) - } - - is OperationSection.MutateRequest -> writable { - // insert the endpoint the bag - rustTemplate("${section.request}.properties_mut().insert(endpoint_result);") - rustTemplate("""if let #{Some}(params) = params { ${section.request}.properties_mut().insert(params); }""", *codegenScope) - } - - else -> emptySection - } - } - - private fun Node.toWritable(): Writable { - val node = this - return writable { - when (node) { - is StringNode -> rustTemplate("#{Some}(${node.value.dq()}.to_string())", *RuntimeType.preludeScope) - is BooleanNode -> rustTemplate("#{Some}(${node.value})", *RuntimeType.preludeScope) - else -> PANIC("unsupported default value: $node") - } - } - } - - private fun builderFields(params: Parameters, section: OperationSection.MutateInput) = writable { - val memberParams = idx.getContextParams(operationShape).toList().sortedBy { it.first.memberName } - val builtInParams = params.toList().filter { it.isBuiltIn } - // first load builtins and their defaults - builtInParams.forEach { param -> - typesGenerator.builtInFor(param, section.config)?.also { defaultValue -> - rust(".set_${param.name.rustName()}(#W)", defaultValue) - } - } - - idx.getClientContextParams(ctx.serviceShape).orNull()?.parameters?.forEach { (name, param) -> - val paramName = EndpointParamsGenerator.memberName(name) - val setterName = EndpointParamsGenerator.setterName(name) - if (param.type == ShapeType.BOOLEAN) { - rust(".$setterName(${section.config}.$paramName)") - } else { - rust(".$setterName(${section.config}.$paramName.clone())") - } - } - - idx.getStaticContextParams(operationShape).orNull()?.parameters?.forEach { (name, param) -> - val setterName = EndpointParamsGenerator.setterName(name) - val value = param.value.toWritable() - rust(".$setterName(#W)", value) - } - - // lastly, allow these to be overridden by members - memberParams.forEach { (memberShape, param) -> - val memberName = ctx.symbolProvider.toMemberName(memberShape) - rust( - ".${EndpointParamsGenerator.setterName(param.name)}(${section.input}.$memberName.clone())", - ) - } - } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt index 90552c3659..7088dbdb02 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt @@ -6,7 +6,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate @@ -14,7 +13,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.Section -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol sealed class OperationSection(name: String) : Section(name) { abstract val customizations: List @@ -23,55 +21,11 @@ sealed class OperationSection(name: String) : Section(name) { data class OperationImplBlock(override val customizations: List) : OperationSection("OperationImplBlock") - // TODO(enableNewSmithyRuntimeCleanup): Delete this customization hook when cleaning up middleware - /** Write additional functions inside the Input's impl block */ - @Deprecated("customization for middleware; won't be used in the orchestrator impl") - data class InputImpl( - override val customizations: List, - val operationShape: OperationShape, - val inputShape: StructureShape, - val protocol: Protocol, - ) : OperationSection("InputImpl") - - // TODO(enableNewSmithyRuntimeCleanup): Delete this customization hook when cleaning up middleware - @Deprecated("customization for middleware; won't be used in the orchestrator impl") - data class MutateInput( - override val customizations: List, - val input: String, - val config: String, - ) : OperationSection("MutateInput") - - // TODO(enableNewSmithyRuntimeCleanup): Delete this customization hook when cleaning up middleware - /** Write custom code into the block that builds an operation - * - * [request]: Name of the variable holding the `aws_smithy_http::Request` - * [config]: Name of the variable holding the service config. - * - * */ - @Deprecated("customization for middleware; won't be used in the orchestrator impl") - data class MutateRequest( - override val customizations: List, - val request: String, - val config: String, - ) : OperationSection("Feature") - - // TODO(enableNewSmithyRuntimeCleanup): Delete this customization hook when cleaning up middleware - @Deprecated("customization for middleware; won't be used in the orchestrator impl") - data class FinalizeOperation( - override val customizations: List, - val operation: String, - val config: String, - ) : OperationSection("Finalize") - data class MutateOutput( override val customizations: List, val operationShape: OperationShape, /** Name of the response headers map (for referring to it in Rust code) */ val responseHeadersName: String, - - // TODO(enableNewSmithyRuntimeCleanup): Remove this flag when switching to the orchestrator - /** Whether the property bag exists in this context */ - val propertyBagAvailable: Boolean, ) : OperationSection("MutateOutput") /** @@ -167,25 +121,4 @@ sealed class OperationSection(name: String) : Section(name) { } } -abstract class OperationCustomization : NamedCustomization() { - // TODO(enableNewSmithyRuntimeCleanup): Delete this when cleaning up middleware - @Deprecated("property for middleware; won't be used in the orchestrator impl") - open fun retryType(): RuntimeType? = null - - // TODO(enableNewSmithyRuntimeCleanup): Delete this when cleaning up middleware - /** - * Does `make_operation` consume the self parameter? - * - * This is required for things like idempotency tokens where the operation can only be sent once - * and an idempotency token will mutate the request. - */ - @Deprecated("property for middleware; won't be used in the orchestrator impl") - open fun consumesSelf(): Boolean = false - - // TODO(enableNewSmithyRuntimeCleanup): Delete this when cleaning up middleware - /** - * Does `make_operation` mutate the self parameter? - */ - @Deprecated("property for middleware; won't be used in the orchestrator impl") - open fun mutSelf(): Boolean = false -} +abstract class OperationCustomization : NamedCustomization() diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt index 9e17d3ccb3..9a3793b766 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt @@ -10,10 +10,9 @@ import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointParamsInterceptorGenerator -import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.MakeOperationGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.RequestSerializerGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ResponseDeserializerGenerator -import software.amazon.smithy.rust.codegen.client.smithy.protocols.HttpBoundProtocolTraitImplGenerator +import software.amazon.smithy.rust.codegen.client.smithy.protocols.ClientHttpBoundProtocolPayloadGenerator import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter @@ -36,15 +35,9 @@ import software.amazon.smithy.rust.codegen.core.util.sdkId open class OperationGenerator( private val codegenContext: ClientCodegenContext, private val protocol: Protocol, - /** - * Operations generate a `make_operation(&config)` method to build a `aws_smithy_http::Operation` that can be dispatched - * This is the serializer side of request dispatch - */ - // TODO(enableNewSmithyRuntimeCleanup): Remove the `makeOperationGenerator` - private val makeOperationGenerator: MakeOperationGenerator, - private val bodyGenerator: ProtocolPayloadGenerator, - // TODO(enableNewSmithyRuntimeCleanup): Remove the `traitGenerator` - private val traitGenerator: HttpBoundProtocolTraitImplGenerator, + private val bodyGenerator: ProtocolPayloadGenerator = ClientHttpBoundProtocolPayloadGenerator( + codegenContext, protocol, + ), ) { private val model = codegenContext.model private val runtimeConfig = codegenContext.runtimeConfig @@ -55,22 +48,10 @@ open class OperationGenerator( */ fun renderOperation( operationWriter: RustWriter, - // TODO(enableNewSmithyRuntimeCleanup): Remove the `inputWriter` since `make_operation` generation is going away - inputWriter: RustWriter, operationShape: OperationShape, codegenDecorator: ClientCodegenDecorator, ) { val operationCustomizations = codegenDecorator.operationCustomizations(codegenContext, operationShape, emptyList()) - val inputShape = operationShape.inputShape(model) - - // impl OperationInputShape { ... } - inputWriter.implBlock(symbolProvider.toSymbol(inputShape)) { - writeCustomizations( - operationCustomizations, - OperationSection.InputImpl(operationCustomizations, operationShape, inputShape, protocol), - ) - } - renderOperationStruct( operationWriter, operationShape, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt index f935da5e94..dedc50f31f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt @@ -11,7 +11,6 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.IdempotencyTokenTrait import software.amazon.smithy.model.traits.PaginatedTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientGenerics import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -38,23 +37,14 @@ fun OperationShape.isPaginated(model: Model) = class PaginatorGenerator private constructor( private val codegenContext: ClientCodegenContext, operation: OperationShape, - private val generics: FluentClientGenerics, - retryClassifier: RuntimeType, ) { companion object { fun paginatorType( codegenContext: ClientCodegenContext, - generics: FluentClientGenerics, operationShape: OperationShape, - retryClassifier: RuntimeType, ): RuntimeType? { return if (operationShape.isPaginated(codegenContext.model)) { - PaginatorGenerator( - codegenContext, - operationShape, - generics, - retryClassifier, - ).paginatorType() + PaginatorGenerator(codegenContext, operationShape).paginatorType() } else { null } @@ -87,15 +77,7 @@ class PaginatorGenerator private constructor( private val codegenScope = arrayOf( *preludeScope, - "generics" to generics.decl, - "bounds" to generics.bounds, "page_size_setter" to pageSizeSetter(), - "send_bounds" to generics.sendBounds( - symbolProvider.toSymbol(operation), - outputType, - errorType, - retryClassifier, - ), // Operation Types "operation" to symbolProvider.toSymbol(operation), @@ -125,15 +107,15 @@ class PaginatorGenerator private constructor( rustTemplate( """ /// Paginator for #{operation:D} - pub struct $paginatorName#{generics:W} { - handle: std::sync::Arc, + pub struct $paginatorName { + handle: std::sync::Arc, builder: #{Builder}, stop_on_duplicate_token: bool, } - impl${generics.inst} ${paginatorName}${generics.inst} #{bounds:W} { + impl $paginatorName { /// Create a new paginator-wrapper - pub(crate) fn new(handle: std::sync::Arc, builder: #{Builder}) -> Self { + pub(crate) fn new(handle: std::sync::Arc, builder: #{Builder}) -> Self { Self { handle, builder, @@ -160,8 +142,7 @@ class PaginatorGenerator private constructor( /// Create the pagination stream /// /// _Note:_ No requests will be dispatched until the stream is used (eg. with [`.next().await`](tokio_stream::StreamExt::next)). - pub fn send(self) -> impl #{Stream} + #{Unpin} - #{send_bounds:W} { + pub fn send(self) -> impl #{Stream} + #{Unpin} { // Move individual fields out of self for the borrow checker let builder = self.builder; let handle = self.handle; @@ -252,7 +233,7 @@ class PaginatorGenerator private constructor( /// /// This paginator automatically flattens results using `$documentedPath`. Queries to the underlying service /// are dispatched lazily. - pub fn items(self) -> #{ItemPaginator}${generics.inst} { + pub fn items(self) -> #{ItemPaginator} { #{ItemPaginator}(self) } """, @@ -271,16 +252,15 @@ class PaginatorGenerator private constructor( /// Flattened paginator for `$paginatorName` /// /// This is created with [`.items()`]($paginatorName::items) - pub struct ${paginatorName}Items#{generics:W}($paginatorName${generics.inst}); + pub struct ${paginatorName}Items($paginatorName); - impl ${generics.inst} ${paginatorName}Items${generics.inst} #{bounds:W} { + impl ${paginatorName}Items { /// Create the pagination stream /// /// _Note: No requests will be dispatched until the stream is used (eg. with [`.next().await`](tokio_stream::StreamExt::next))._ /// /// To read the entirety of the paginator, use [`.collect::, _>()`](tokio_stream::StreamExt::collect). - pub fn send(self) -> impl #{Stream} + #{Unpin} - #{send_bounds:W} { + pub fn send(self) -> impl #{Stream} + #{Unpin} { #{fn_stream}::TryFlatMap::new(self.0.send()).flat_map(|page| #{extract_items}(page).unwrap_or_default().into_iter()) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationDecorator.kt index 8859cc598f..608a6afea7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationDecorator.kt @@ -10,9 +10,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.customize.Section sealed class CustomizableOperationSection(name: String) : Section(name) { /** Write custom code into a customizable operation's impl block */ - data class CustomizableOperationImpl( - val isRuntimeModeOrchestrator: Boolean, - ) : CustomizableOperationSection("CustomizableOperationImpl") + object CustomizableOperationImpl : CustomizableOperationSection("CustomizableOperationImpl") } abstract class CustomizableOperationCustomization : NamedCustomization() diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt index 8e858b1657..bfac81dd16 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt @@ -7,9 +7,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators.client import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule -import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.core.rustlang.GenericTypeArg -import software.amazon.smithy.rust.codegen.core.rustlang.RustGenerics import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility @@ -25,102 +22,16 @@ import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizat * fluent client builders. */ class CustomizableOperationGenerator( - private val codegenContext: ClientCodegenContext, - private val generics: FluentClientGenerics, + codegenContext: ClientCodegenContext, private val customizations: List, ) { private val runtimeConfig = codegenContext.runtimeConfig - private val smithyHttp = CargoDependency.smithyHttp(runtimeConfig).toType() - private val smithyTypes = CargoDependency.smithyTypes(runtimeConfig).toType() - - private fun renderCustomizableOperationModule(writer: RustWriter) { - val operationGenerics = RustGenerics(GenericTypeArg("O"), GenericTypeArg("Retry")) - val handleGenerics = generics.toRustGenerics() - val combinedGenerics = operationGenerics + handleGenerics - - val codegenScope = arrayOf( - *preludeScope, - "Arc" to RuntimeType.Arc, - "Infallible" to RuntimeType.stdConvert.resolve("Infallible"), - // SDK Types - "HttpRequest" to RuntimeType.HttpRequest, - "handle_generics_decl" to handleGenerics.declaration(), - "handle_generics_bounds" to handleGenerics.bounds(), - "operation_generics_decl" to operationGenerics.declaration(), - "combined_generics_decl" to combinedGenerics.declaration(), - "customize_module" to ClientRustModule.Client.customize, - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - ) - - writer.rustTemplate( - """ - /// A wrapper type for [`Operation`](aws_smithy_http::operation::Operation)s that allows for - /// customization of the operation before it is sent. A `CustomizableOperation` may be sent - /// by calling its [`.send()`][#{customize_module}::CustomizableOperation::send] method. - ##[derive(Debug)] - pub struct CustomizableOperation#{combined_generics_decl:W} { - pub(crate) handle: #{Arc}, - pub(crate) operation: Operation#{operation_generics_decl:W}, - } - - impl#{combined_generics_decl:W} CustomizableOperation#{combined_generics_decl:W} - where - #{handle_generics_bounds:W} - { - /// Allows for customizing the operation's request - pub fn map_request( - mut self, - f: impl #{FnOnce}(#{HttpRequest}<#{SdkBody}>) -> #{Result}<#{HttpRequest}<#{SdkBody}>, E>, - ) -> #{Result} { - let (request, response) = self.operation.into_request_response(); - let request = request.augment(|req, _props| f(req))?; - self.operation = Operation::from_parts(request, response); - #{Ok}(self) - } - - /// Convenience for `map_request` where infallible direct mutation of request is acceptable - pub fn mutate_request(self, f: impl #{FnOnce}(&mut #{HttpRequest}<#{SdkBody}>)) -> Self { - self.map_request(|mut req| { - f(&mut req); - #{Result}::<_, #{Infallible}>::Ok(req) - }) - .expect("infallible") - } - - /// Allows for customizing the entire operation - pub fn map_operation( - mut self, - f: impl #{FnOnce}(Operation#{operation_generics_decl:W}) -> #{Result}, - ) -> #{Result} { - self.operation = f(self.operation)?; - #{Ok}(self) - } - - /// Direct access to read the HTTP request - pub fn request(&self) -> &#{HttpRequest}<#{SdkBody}> { - self.operation.request() - } - - /// Direct access to mutate the HTTP request - pub fn request_mut(&mut self) -> &mut #{HttpRequest}<#{SdkBody}> { - self.operation.request_mut() - } - - #{additional_methods} - } - """, - *codegenScope, - "additional_methods" to writable { - writeCustomizations(customizations, CustomizableOperationSection.CustomizableOperationImpl(false)) - }, - ) - } fun render(crate: RustCrate) { val codegenScope = arrayOf( *preludeScope, "CustomizableOperation" to ClientRustModule.Client.customize.toType() - .resolve("orchestrator::CustomizableOperation"), + .resolve("CustomizableOperation"), "CustomizableSend" to ClientRustModule.Client.customize.toType() .resolve("internal::CustomizableSend"), "HttpRequest" to RuntimeType.smithyRuntimeApi(runtimeConfig) @@ -144,134 +55,116 @@ class CustomizableOperationGenerator( ) val customizeModule = ClientRustModule.Client.customize - crate.withModule(customizeModule) { renderConvenienceAliases(customizeModule, this) - // TODO(enableNewSmithyRuntimeCleanup): Render it directly under the customize module when CustomizableOperation - // in the middleware has been removed. - withInlineModule( - RustModule.new( - "orchestrator", - Visibility.PUBLIC, - true, - customizeModule, - documentationOverride = "Module for defining types for `CustomizableOperation` in the orchestrator", - ), - null, - ) { - rustTemplate( - """ - /// `CustomizableOperation` allows for configuring a single operation invocation before it is sent. - pub struct CustomizableOperation { - pub(crate) customizable_send: #{Box}>, - pub(crate) config_override: #{Option}, - pub(crate) interceptors: Vec<#{SharedInterceptor}>, - pub(crate) runtime_plugins: Vec<#{SharedRuntimePlugin}>, - } - - impl CustomizableOperation { - /// Adds an [`Interceptor`](#{Interceptor}) that runs at specific stages of the request execution pipeline. - /// - /// Note that interceptors can also be added to `CustomizableOperation` by `config_override`, - /// `map_request`, and `mutate_request` (the last two are implemented via interceptors under the hood). - /// The order in which those user-specified operation interceptors are invoked should not be relied upon - /// as it is an implementation detail. - pub fn interceptor(mut self, interceptor: impl #{Interceptor} + 'static) -> Self { - self.interceptors.push(#{SharedInterceptor}::new(interceptor)); - self - } - - /// Adds a runtime plugin. - ##[allow(unused)] - pub(crate) fn runtime_plugin(mut self, runtime_plugin: impl #{RuntimePlugin} + 'static) -> Self { - self.runtime_plugins.push(#{SharedRuntimePlugin}::new(runtime_plugin)); - self - } - - /// Allows for customizing the operation's request. - pub fn map_request(mut self, f: F) -> Self - where - F: #{Fn}(#{HttpRequest}) -> #{Result}<#{HttpRequest}, MapE> - + #{Send} - + #{Sync} - + 'static, - MapE: ::std::error::Error + #{Send} + #{Sync} + 'static, - { - self.interceptors.push( - #{SharedInterceptor}::new( - #{MapRequestInterceptor}::new(f), - ), - ); - self - } + rustTemplate( + """ + /// `CustomizableOperation` allows for configuring a single operation invocation before it is sent. + pub struct CustomizableOperation { + pub(crate) customizable_send: #{Box}>, + pub(crate) config_override: #{Option}, + pub(crate) interceptors: Vec<#{SharedInterceptor}>, + pub(crate) runtime_plugins: Vec<#{SharedRuntimePlugin}>, + } - /// Convenience for `map_request` where infallible direct mutation of request is acceptable. - pub fn mutate_request(mut self, f: F) -> Self - where - F: #{Fn}(&mut http::Request<#{SdkBody}>) + #{Send} + #{Sync} + 'static, - { - self.interceptors.push( - #{SharedInterceptor}::new( - #{MutateRequestInterceptor}::new(f), - ), - ); - self - } + impl CustomizableOperation { + /// Adds an [`Interceptor`](#{Interceptor}) that runs at specific stages of the request execution pipeline. + /// + /// Note that interceptors can also be added to `CustomizableOperation` by `config_override`, + /// `map_request`, and `mutate_request` (the last two are implemented via interceptors under the hood). + /// The order in which those user-specified operation interceptors are invoked should not be relied upon + /// as it is an implementation detail. + pub fn interceptor(mut self, interceptor: impl #{Interceptor} + 'static) -> Self { + self.interceptors.push(#{SharedInterceptor}::new(interceptor)); + self + } - /// Overrides config for a single operation invocation. - /// - /// `config_override` is applied to the operation configuration level. - /// The fields in the builder that are `Some` override those applied to the service - /// configuration level. For instance, - /// - /// Config A overridden by Config B == Config C - /// field_1: None, field_1: Some(v2), field_1: Some(v2), - /// field_2: Some(v1), field_2: Some(v2), field_2: Some(v2), - /// field_3: Some(v1), field_3: None, field_3: Some(v1), - pub fn config_override( - mut self, - config_override: impl #{Into}, - ) -> Self { - self.config_override = Some(config_override.into()); - self - } + /// Adds a runtime plugin. + ##[allow(unused)] + pub(crate) fn runtime_plugin(mut self, runtime_plugin: impl #{RuntimePlugin} + 'static) -> Self { + self.runtime_plugins.push(#{SharedRuntimePlugin}::new(runtime_plugin)); + self + } - /// Sends the request and returns the response. - pub async fn send( - self, - ) -> #{SendResult} - where - E: std::error::Error + #{Send} + #{Sync} + 'static, - { - let mut config_override = if let Some(config_override) = self.config_override { - config_override - } else { - crate::config::Builder::new() - }; + /// Allows for customizing the operation's request. + pub fn map_request(mut self, f: F) -> Self + where + F: #{Fn}(#{HttpRequest}) -> #{Result}<#{HttpRequest}, MapE> + + #{Send} + + #{Sync} + + 'static, + MapE: ::std::error::Error + #{Send} + #{Sync} + 'static, + { + self.interceptors.push( + #{SharedInterceptor}::new( + #{MapRequestInterceptor}::new(f), + ), + ); + self + } - self.interceptors.into_iter().for_each(|interceptor| { - config_override.push_interceptor(interceptor); - }); - self.runtime_plugins.into_iter().for_each(|plugin| { - config_override.push_runtime_plugin(plugin); - }); + /// Convenience for `map_request` where infallible direct mutation of request is acceptable. + pub fn mutate_request(mut self, f: F) -> Self + where + F: #{Fn}(&mut http::Request<#{SdkBody}>) + #{Send} + #{Sync} + 'static, + { + self.interceptors.push( + #{SharedInterceptor}::new( + #{MutateRequestInterceptor}::new(f), + ), + ); + self + } - (self.customizable_send)(config_override).await - } + /// Overrides config for a single operation invocation. + /// + /// `config_override` is applied to the operation configuration level. + /// The fields in the builder that are `Some` override those applied to the service + /// configuration level. For instance, + /// + /// | Config A | overridden by Config B | = Config C | + /// |--------------------|------------------------|--------------------| + /// | field_1: None, | field_1: Some(v2), | field_1: Some(v2), | + /// | field_2: Some(v1), | field_2: Some(v2), | field_2: Some(v2), | + /// | field_3: Some(v1), | field_3: None, | field_3: Some(v1), | + pub fn config_override( + mut self, + config_override: impl #{Into}, + ) -> Self { + self.config_override = Some(config_override.into()); + self + } - #{additional_methods} + /// Sends the request and returns the response. + pub async fn send( + self, + ) -> #{SendResult} + where + E: std::error::Error + #{Send} + #{Sync} + 'static, + { + let mut config_override = self.config_override.unwrap_or_default(); + self.interceptors.into_iter().for_each(|interceptor| { + config_override.push_interceptor(interceptor); + }); + self.runtime_plugins.into_iter().for_each(|plugin| { + config_override.push_runtime_plugin(plugin); + }); + + (self.customizable_send)(config_override).await } - """, - *codegenScope, - "additional_methods" to writable { - writeCustomizations( - customizations, - CustomizableOperationSection.CustomizableOperationImpl(true), - ) - }, - ) - } + + #{additional_methods} + } + """, + *codegenScope, + "additional_methods" to writable { + writeCustomizations( + customizations, + CustomizableOperationSection.CustomizableOperationImpl, + ) + }, + ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt index 9af0bae68f..5234f6fe59 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt @@ -34,11 +34,8 @@ class FluentClientDecorator : ClientCodegenDecorator { return } - val generics = NoClientGenerics(codegenContext.runtimeConfig) - FluentClientGenerator( codegenContext, - generics = generics, customizations = listOf(GenericFluentClient(codegenContext)), ).render(rustCrate) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt index b83cb7a860..448b576a9d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt @@ -8,7 +8,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators.client import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.docsTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.util.inputShape @@ -22,157 +21,32 @@ object FluentClientDocs { """ Client for calling $serviceName. - #### Client types and purposes - - Clients generated by smithy-rs have two separate client layers: - - 1. The Smithy [`Client`](#{aws_smithy_client}::Client): A _lower level client_ that is not tied - to the service and directly operates on operation structs. A Smithy client is composed of a - connector, middleware, and retry strategy. - 2. The "fluent" [`Client`]: A _higher level client_ that is convenient to use. - - The vast majority of use-cases don't require using the Smithy client, so it is usually only relevant - for client construction. Because of this, this documentation will refer to the fluent client as simply - the "client". The Smithy client is only relevant when customizing the connector, middleware, or - retry strategy, or for even more advanced use cases. - #### Constructing a `Client` - A fluent [`Client`] is composed of a Smithy client and service configuration. In order to - construct one, a Smithy client must be created first, and this is done using - the [`client::Builder`](crate::client::Builder) struct: - - ```rust,no_run - let smithy_client = $moduleUseName::client::Builder::new() - // Use the default HTTPS connector - .dyn_https_connector(Default::default()) - // Use a no-op middleware - .middleware_fn(|request| request) - // Build a type-erased Smithy client - .build_dyn(); - ``` + A `Client` requires a config in order to be constructed. With the default set of Cargo features, + this config will only require an endpoint to produce a functioning client. However, some Smithy + features will require additional configuration. For example, `@auth` requires some kind of identity + or identity resolver to be configured. The config is used to customize various aspects of the client, + such as: - The client builder has generics `C`, `M`, and `R` representing the connector, middleware, and - retry strategy: + - [HTTP Connector](crate::config::Builder::http_connector) + - [Retry](crate::config::Builder::retry_config) + - [Timeouts](crate::config::Builder::timeout_config) + - [... and more](crate::config::Builder) - - A connector (`C`) specifies how HTTP requests are translated into HTTP responses. This will typically be - an HTTP client (like `hyper`), but you can also provide your own, like a mock connector for testing. - - Middleware (`M`) modifies requests prior to them being sent to the service. Most commonly, middleware decide - what endpoint the requests should be sent to, as well as perform authentication and authorization (such - as HTTP basic auth or AWS SigV4). You can also have middleware that performs request/response tracing, - throttling, or other middleware-like tasks. - - A retry strategy (`R`) dictates the behavior for requests that fail. The default, - [`RetryMode::Standard`](aws_smithy_types::retry::RetryMode::Standard) is generally what you want since - it provides a well-vetted exponential backoff retry implementation. - - Once the Smithy client is created, a service config and fluent client can be created. Generally, you - want to call [`Client::with_config`], which takes a Smithy client and the service [`Config`](crate::Config). - The config is constructed using the [builder pattern], and has several builder methods to further - customize the client. - - In _most_ circumstances, you will want to use the following pattern to construct a client: + Below is a minimal example of how to create a client: ```rust,no_run - let smithy_client = $moduleUseName::client::Builder::new() - .dyn_https_connector(Default::default()) - ## /* - .middleware(/* discussed below */) - ## */ - ## .middleware_fn(|r| r) - .build_dyn(); - - let config = $moduleUseName::Config::builder().build(); - let client = $moduleUseName::Client::with_config(smithy_client, config); + let config = $moduleUseName::Config::builder() + .endpoint_url("http://localhost:1234") + .build(); + let client = $moduleUseName::Client::from_conf(config); ``` _Note:_ Client construction is expensive due to connection thread pool initialization, and should be done - once at application start-up. - - For middleware, you'll want to use whatever matches the routing, authentication, and authorization - required by the target service. For example, for the AWS SDK which uses [SigV4-signed requests], the - middleware looks like this: - - ```rust,ignore - use aws_endpoint::AwsEndpointStage; - use aws_http::auth::CredentialsStage; - use aws_http::recursion_detection::RecursionDetectionStage; - use aws_http::user_agent::UserAgentStage; - use aws_sig_auth::middleware::SigV4SigningStage; - use aws_sig_auth::signer::SigV4Signer; - use aws_smithy_client::retry::Config as RetryConfig; - use aws_smithy_http_tower::map_request::{AsyncMapRequestLayer, MapRequestLayer}; - use std::fmt::Debug; - use tower::layer::util::{Identity, Stack}; - use tower::ServiceBuilder; - - type AwsMiddlewareStack = Stack< - MapRequestLayer, - Stack< - MapRequestLayer, - Stack< - AsyncMapRequestLayer, - Stack< - MapRequestLayer, - Stack, Identity>, - >, - >, - >, - >; - - /// AWS Middleware Stack - /// - /// This implements the middleware stack for this service. It will: - /// 1. Load credentials asynchronously into the property bag - /// 2. Sign the request with SigV4 - /// 3. Resolve an Endpoint for the request - /// 4. Add a user agent to the request - ##[derive(Debug, Default, Clone)] - ##[non_exhaustive] - pub struct AwsMiddleware; - - impl AwsMiddleware { - /// Create a new `AwsMiddleware` stack - /// - /// Note: `AwsMiddleware` holds no state. - pub fn new() -> Self { - AwsMiddleware::default() - } - } - - // define the middleware stack in a non-generic location to reduce code bloat. - fn base() -> ServiceBuilder { - let credential_provider = AsyncMapRequestLayer::for_mapper(CredentialsStage::new()); - let signer = MapRequestLayer::for_mapper(SigV4SigningStage::new(SigV4Signer::new())); - let endpoint_resolver = MapRequestLayer::for_mapper(AwsEndpointStage); - let user_agent = MapRequestLayer::for_mapper(UserAgentStage::new()); - let recursion_detection = MapRequestLayer::for_mapper(RecursionDetectionStage::new()); - // These layers can be considered as occurring in order, that is: - // 1. Resolve an endpoint - // 2. Add a user agent - // 3. Acquire credentials - // 4. Sign with credentials - // (5. Dispatch over the wire) - ServiceBuilder::new() - .layer(endpoint_resolver) - .layer(user_agent) - .layer(credential_provider) - .layer(signer) - .layer(recursion_detection) - } - - impl tower::Layer for AwsMiddleware { - type Service = >::Service; - - fn layer(&self, inner: S) -> Self::Service { - base().service(inner) - } - } - ``` - - [builder pattern]: https://rust-lang.github.io/api-guidelines/type-safety.html##builders-enable-construction-of-complex-values-c-builder - [SigV4-signed requests]: https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html""${'"'}, + once at application start-up. Cloning a client is cheap (it's just an [`Arc`](std::sync::Arc) under the hood), + so creating it once at start-up and cloning it around the application as needed is recommended. """.trimIndent(), - "aws_smithy_client" to CargoDependency.smithyClient(codegenContext.runtimeConfig).toDevDependency().toType(), ) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index fe6e44793c..3684ae1253 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -58,10 +58,7 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase class FluentClientGenerator( private val codegenContext: ClientCodegenContext, private val reexportSmithyClientBuilder: Boolean = true, - private val generics: FluentClientGenerics, private val customizations: List = emptyList(), - private val retryClassifier: RuntimeType = RuntimeType.smithyHttp(codegenContext.runtimeConfig) - .resolve("retry::DefaultResponseRetryClassifier"), ) { companion object { fun clientOperationFnName(operationShape: OperationShape, symbolProvider: RustSymbolProvider): String = @@ -85,7 +82,7 @@ class FluentClientGenerator( fun render(crate: RustCrate, customizableOperationCustomizations: List = emptyList()) { renderFluentClient(crate) - val customizableOperationGenerator = CustomizableOperationGenerator(codegenContext, generics, customizableOperationCustomizations) + val customizableOperationGenerator = CustomizableOperationGenerator(codegenContext, customizableOperationCustomizations) operations.forEach { operation -> crate.withModule(symbolProvider.moduleForBuilder(operation)) { renderFluentBuilder(operation) @@ -123,9 +120,6 @@ class FluentClientGenerator( "RetryConfig" to RuntimeType.smithyTypes(runtimeConfig).resolve("retry::RetryConfig"), "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), "TimeoutConfig" to RuntimeType.smithyTypes(runtimeConfig).resolve("timeout::TimeoutConfig"), - // TODO(enableNewSmithyRuntimeCleanup): Delete the generics when cleaning up middleware - "generics_decl" to generics.decl, - "smithy_inst" to generics.smithyInst, ) rustTemplate( """ @@ -172,22 +166,6 @@ class FluentClientGenerator( pub fn config(&self) -> &crate::Config { &self.handle.conf } - - ##[doc(hidden)] - // TODO(enableNewSmithyRuntimeCleanup): Delete this function when cleaning up middleware - // This is currently kept around so the tests still compile in both modes - /// Creates a client with the given service configuration. - pub fn with_config(_client: #{client}::Client, conf: crate::Config) -> Self { - Self::from_conf(conf) - } - - ##[doc(hidden)] - // TODO(enableNewSmithyRuntimeCleanup): Delete this function when cleaning up middleware - // This is currently kept around so the tests still compile in both modes - /// Returns the client's configuration. - pub fn conf(&self) -> &crate::Config { - &self.handle.conf - } } """, *clientScope, @@ -203,9 +181,8 @@ class FluentClientGenerator( val privateModule = RustModule.private(moduleName, parent = ClientRustModule.client) crate.withModule(privateModule) { rustBlockTemplate( - "impl${generics.inst} super::Client${generics.inst} #{bounds:W}", + "impl super::Client", "client" to RuntimeType.smithyClient(runtimeConfig), - "bounds" to generics.bounds, ) { val fullPath = operation.fullyQualifiedFluentBuilder(symbolProvider) val maybePaginated = if (operation.isPaginated(model)) { @@ -252,7 +229,7 @@ class FluentClientGenerator( rustTemplate( """ - pub fn $fnName(&self) -> #{FluentBuilder}${generics.inst} { + pub fn $fnName(&self) -> #{FluentBuilder} { #{FluentBuilder}::new(self.handle.clone()) } """, @@ -277,16 +254,13 @@ class FluentClientGenerator( rustTemplate( """ /// Sends a request with this input using the given client. - pub async fn send_with${generics.inst}( - self, - client: &crate::Client${generics.inst} - ) -> #{Result}< + pub async fn send_with(self, client: &crate::Client) -> #{Result}< #{OperationOutput}, #{SdkError}< #{OperationError}, #{RawResponseType} > - > #{send_bounds:W} #{boundsWithoutWhereClause:W} { + > { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; fluent_builder.send().await @@ -300,8 +274,6 @@ class FluentClientGenerator( "OperationOutput" to outputType, "SdkError" to RuntimeType.sdkError(runtimeConfig), "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), - "boundsWithoutWhereClause" to generics.boundsWithoutWhereClause, - "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), ) } @@ -313,33 +285,29 @@ class FluentClientGenerator( deprecatedShape(operation) Attribute(derive(derives.toSet())).render(this) withBlockTemplate( - "pub struct $builderName#{generics:W} {", + "pub struct $builderName {", "}", - "generics" to generics.decl, ) { rustTemplate( """ - handle: #{Arc}, + handle: #{Arc}, inner: #{Inner}, """, "Inner" to symbolProvider.symbolForBuilder(input), "Arc" to RuntimeType.Arc, - "generics" to generics.decl, ) rustTemplate("config_override: #{Option},", *preludeScope) } rustBlockTemplate( - "impl${generics.inst} $builderName${generics.inst} #{bounds:W}", + "impl $builderName", "client" to RuntimeType.smithyClient(runtimeConfig), - "bounds" to generics.bounds, ) { rust("/// Creates a new `${operationSymbol.name}`.") withBlockTemplate( - "pub(crate) fn new(handle: #{Arc}) -> Self {", + "pub(crate) fn new(handle: #{Arc}) -> Self {", "}", "Arc" to RuntimeType.Arc, - "generics" to generics.decl, ) { withBlockTemplate( "Self {", @@ -361,7 +329,7 @@ class FluentClientGenerator( val orchestratorScope = arrayOf( *preludeScope, "CustomizableOperation" to ClientRustModule.Client.customize.toType() - .resolve("orchestrator::CustomizableOperation"), + .resolve("CustomizableOperation"), "HttpResponse" to RuntimeType.smithyRuntimeApi(runtimeConfig) .resolve("client::orchestrator::HttpResponse"), "Operation" to operationSymbol, @@ -442,14 +410,14 @@ class FluentClientGenerator( """, ) - PaginatorGenerator.paginatorType(codegenContext, generics, operation, retryClassifier) + PaginatorGenerator.paginatorType(codegenContext, operation) ?.also { paginatorType -> rustTemplate( """ /// Create a paginator for this request /// /// Paginators are used by calling [`send().await`](#{Paginator}::send) which returns a `Stream`. - pub fn into_paginator(self) -> #{Paginator}${generics.inst} { + pub fn into_paginator(self) -> #{Paginator} { #{Paginator}::new(self.handle, self.inner) } """, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt deleted file mode 100644 index 77b4a46019..0000000000 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.client.smithy.generators.client - -import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.rust.codegen.core.rustlang.GenericTypeArg -import software.amazon.smithy.rust.codegen.core.rustlang.RustGenerics -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.writable -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType - -// TODO(enableNewSmithyRuntimeCleanup): Delete this client generics on/off switch headache -interface FluentClientGenerics { - /** Declaration with defaults set */ - val decl: Writable - - /** Instantiation of the Smithy client generics */ - val smithyInst: Writable - - /** Instantiation */ - val inst: String - - /** Bounds */ - val bounds: Writable - - /** Bounds for generated `send()` functions */ - fun sendBounds(operation: Symbol, operationOutput: Symbol, operationError: Symbol, retryClassifier: RuntimeType): Writable - - /** Convert this `FluentClientGenerics` into the more general `RustGenerics` */ - fun toRustGenerics(): RustGenerics - - /** bounds without where clause. If bounds does is not prefixed with `where\n`, then it gets the same value. **/ - val boundsWithoutWhereClause: Writable -} - -class NoClientGenerics(private val runtimeConfig: RuntimeConfig) : FluentClientGenerics { - /** Declaration with defaults set */ - override val decl = writable { } - - /** Instantiation of the Smithy client generics */ - override val smithyInst = writable { - rustTemplate( - "<#{DynConnector}, #{DynMiddleware}<#{DynConnector}>>", - "DynConnector" to RuntimeType.smithyClient(runtimeConfig).resolve("erase::DynConnector"), - "DynMiddleware" to RuntimeType.smithyClient(runtimeConfig).resolve("erase::DynMiddleware"), - ) - } - - /** Instantiation */ - override val inst = "" - - /** Trait bounds */ - override val bounds = writable { } - - override val boundsWithoutWhereClause = writable {} - - /** Bounds for generated `send()` functions */ - override fun sendBounds( - operation: Symbol, - operationOutput: Symbol, - operationError: Symbol, - retryClassifier: RuntimeType, - ): Writable = - writable { } - - override fun toRustGenerics() = RustGenerics() -} - -data class FlexibleClientGenerics( - val connectorDefault: RuntimeType?, - val middlewareDefault: RuntimeType?, - val retryDefault: RuntimeType?, - val client: RuntimeType, -) : FluentClientGenerics { - /** Declaration with defaults set */ - override val decl = writable { - rustTemplate( - "", - "c" to defaultType(connectorDefault), - "m" to defaultType(middlewareDefault), - "r" to defaultType(retryDefault), - ) - } - - /** Instantiation of the Smithy client generics */ - override val smithyInst = writable { rust("") } - - /** Instantiation */ - override val inst: String = "" - - /** Trait bounds */ - override val bounds = writable { - rustTemplate( - """ - where - #{bounds} - """, - "bounds" to boundsWithoutWhereClause, - ) - } - - override val boundsWithoutWhereClause = writable { - rustTemplate( - """ - C: #{client}::bounds::SmithyConnector, - M: #{client}::bounds::SmithyMiddleware, - R: #{client}::retry::NewRequestPolicy, - """, - "client" to client, - ) - } - - /** Bounds for generated `send()` functions */ - override fun sendBounds(operation: Symbol, operationOutput: Symbol, operationError: Symbol, retryClassifier: RuntimeType): Writable = writable { - rustTemplate( - """ - where - R::Policy: #{client}::bounds::SmithyRetryPolicy< - #{Operation}, - #{OperationOutput}, - #{OperationError}, - #{RetryClassifier} - >, - """, - "client" to client, - "Operation" to operation, - "OperationOutput" to operationOutput, - "OperationError" to operationError, - "RetryClassifier" to retryClassifier, - ) - } - - override fun toRustGenerics(): RustGenerics = RustGenerics( - GenericTypeArg("C", client.resolve("bounds::SmithyConnector")), - GenericTypeArg("M", client.resolve("bounds::SmithyMiddleware")), - GenericTypeArg("R", client.resolve("retry::NewRequestPolicy")), - ) - - private fun defaultType(default: RuntimeType?) = writable { - default?.also { rust("= #T", default) } - } -} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt deleted file mode 100644 index d79817df40..0000000000 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.client.smithy.generators.protocol - -import software.amazon.smithy.model.shapes.BlobShape -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.client.smithy.generators.http.RequestBindingGenerator -import software.amazon.smithy.rust.codegen.client.smithy.protocols.ClientAdditionalPayloadContext -import software.amazon.smithy.rust.codegen.core.rustlang.Attribute -import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.rustlang.docs -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.withBlock -import software.amazon.smithy.rust.codegen.core.rustlang.withBlockTemplate -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope -import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations -import software.amazon.smithy.rust.codegen.core.smithy.generators.operationBuildError -import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolPayloadGenerator -import software.amazon.smithy.rust.codegen.core.smithy.protocols.HttpLocation -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol -import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.core.util.findStreamingMember -import software.amazon.smithy.rust.codegen.core.util.inputShape -import software.amazon.smithy.rust.codegen.core.util.letIf -import software.amazon.smithy.rust.codegen.core.util.sdkId - -// TODO(enableNewSmithyRuntimeCleanup): Delete this class when cleaning up `enableNewSmithyRuntime` -/** Generates the `make_operation` function on input structs */ -open class MakeOperationGenerator( - protected val codegenContext: CodegenContext, - private val protocol: Protocol, - private val bodyGenerator: ProtocolPayloadGenerator, - private val public: Boolean, - /** Whether to include default values for content-length and content-type */ - private val includeDefaultPayloadHeaders: Boolean, - private val functionName: String = "make_operation", -) { - protected val model = codegenContext.model - protected val runtimeConfig = codegenContext.runtimeConfig - protected val symbolProvider = codegenContext.symbolProvider - private val httpBindingResolver = protocol.httpBindingResolver - private val defaultClassifier = RuntimeType.smithyHttp(runtimeConfig) - .resolve("retry::DefaultResponseRetryClassifier") - - private val sdkId = codegenContext.serviceShape.sdkId() - - private val codegenScope = arrayOf( - *preludeScope, - "config" to ClientRustModule.config, - "header_util" to RuntimeType.smithyHttp(runtimeConfig).resolve("header"), - "http" to RuntimeType.Http, - "operation" to RuntimeType.operationModule(runtimeConfig), - "HttpRequestBuilder" to RuntimeType.HttpRequestBuilder, - "OpBuildError" to runtimeConfig.operationBuildError(), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - "SharedPropertyBag" to RuntimeType.smithyHttp(runtimeConfig).resolve("property_bag::SharedPropertyBag"), - "RetryMode" to RuntimeType.smithyTypes(runtimeConfig).resolve("retry::RetryMode"), - ) - - fun generateMakeOperation( - implBlockWriter: RustWriter, - shape: OperationShape, - customizations: List, - ) { - val operationName = symbolProvider.toSymbol(shape).name - val baseReturnType = buildOperationType(implBlockWriter, shape, customizations) - val returnType = - "#{Result}<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" - val outputSymbol = symbolProvider.toSymbol(shape) - - val takesOwnership = bodyGenerator.payloadMetadata(shape).takesOwnership - val mut = customizations.any { it.mutSelf() } - val consumes = customizations.any { it.consumesSelf() } || takesOwnership - val self = "self".letIf(mut) { "mut $it" }.letIf(!consumes) { "&$it" } - val fnType = if (public) "pub async fn" else "async fn" - - implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) - // For codegen simplicity - Attribute.AllowUnusedMut.render(implBlockWriter) - // For codegen simplicity, allow `let x = ...; x` - Attribute.AllowClippyLetAndReturn.render(implBlockWriter) - // Allows builders that don’t consume the input borrow - Attribute.AllowClippyNeedlessBorrow.render(implBlockWriter) - - implBlockWriter.rustBlockTemplate( - "$fnType $functionName($self, _config: &#{config}::Config) -> $returnType", - *codegenScope, - ) { - rustTemplate( - """ - assert_ne!(_config.retry_config().map(|rc| rc.mode()), #{Option}::Some(#{RetryMode}::Adaptive), "Adaptive retry mode is unsupported, please use Standard mode or disable retries."); - """, - *codegenScope, - ) - writeCustomizations(customizations, OperationSection.MutateInput(customizations, "self", "_config")) - - withBlock("let mut request = {", "};") { - createHttpRequest(this, shape) - } - rustTemplate("let mut properties = #{SharedPropertyBag}::new();", *codegenScope) - - // When the payload is a `ByteStream`, `into_inner()` already returns an `SdkBody`, so we mute this - // Clippy warning to make the codegen a little simpler in that case. - Attribute.AllowClippyUselessConversion.render(this) - withBlockTemplate("let body = #{SdkBody}::from(", ");", *codegenScope) { - bodyGenerator.generatePayload( - this, - "self", - shape, - ClientAdditionalPayloadContext(propertyBagAvailable = true), - ) - val streamingMember = shape.inputShape(model).findStreamingMember(model) - val isBlobStreaming = streamingMember != null && model.expectShape(streamingMember.target) is BlobShape - if (isBlobStreaming) { - // Consume the `ByteStream` into its inner `SdkBody`. - rust(".into_inner()") - } - } - if (includeDefaultPayloadHeaders && needsContentLength(shape)) { - rustTemplate( - """ - if let #{Some}(content_length) = body.content_length() { - request = #{header_util}::set_request_header_if_absent(request, #{http}::header::CONTENT_LENGTH, content_length); - } - """, - *codegenScope, - ) - } - rust("""let request = request.body(body).expect("should be valid request");""") - rustTemplate( - """ - let mut request = #{operation}::Request::from_parts(request, properties); - """, - *codegenScope, - ) - writeCustomizations(customizations, OperationSection.MutateRequest(customizations, "request", "_config")) - rustTemplate( - """ - let op = #{operation}::Operation::new(request, #{OperationType}::new()) - .with_metadata(#{operation}::Metadata::new(${operationName.dq()}, ${sdkId.dq()})); - """, - *codegenScope, - "OperationType" to symbolProvider.toSymbol(shape), - ) - writeCustomizations(customizations, OperationSection.FinalizeOperation(customizations, "op", "_config")) - rustTemplate("#{Ok}(op)", *codegenScope) - } - } - - private fun buildOperationType( - writer: RustWriter, - shape: OperationShape, - customizations: List, - ): String { - val operationT = RuntimeType.operation(runtimeConfig) - val output = buildOperationTypeOutput(writer, shape) - val retry = buildOperationTypeRetry(writer, customizations) - return with(writer) { "${format(operationT)}<$output, $retry>" } - } - - private fun buildOperationTypeOutput(writer: RustWriter, shape: OperationShape): String = - writer.format(symbolProvider.toSymbol(shape)) - - private fun buildOperationTypeRetry(writer: RustWriter, customizations: List): String = - (customizations.firstNotNullOfOrNull { it.retryType() } ?: defaultClassifier).let { writer.format(it) } - - private fun needsContentLength(operationShape: OperationShape): Boolean { - return protocol.httpBindingResolver.requestBindings(operationShape) - .any { it.location == HttpLocation.DOCUMENT || it.location == HttpLocation.PAYLOAD } - } - - open fun createHttpRequest(writer: RustWriter, operationShape: OperationShape) { - val httpBindingGenerator = RequestBindingGenerator( - codegenContext, - protocol, - operationShape, - ) - val contentType = httpBindingResolver.requestContentType(operationShape) - httpBindingGenerator.renderUpdateHttpBuilder(writer) - - writer.rust("let mut builder = update_http_builder(&self, #T::new())?;", RuntimeType.HttpRequestBuilder) - if (includeDefaultPayloadHeaders && contentType != null) { - writer.rustTemplate( - "builder = #{header_util}::set_request_header_if_absent(builder, #{http}::header::CONTENT_TYPE, ${contentType.dq()});", - *codegenScope, - ) - } - for (header in protocol.additionalRequestHeaders(operationShape)) { - writer.rustTemplate( - """ - builder = #{header_util}::set_request_header_if_absent( - builder, - #{http}::header::HeaderName::from_static(${header.first.dq()}), - ${header.second.dq()} - ); - """, - *codegenScope, - ) - } - writer.rust("builder") - } -} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt index 61b0c42047..608cd5869a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt @@ -55,21 +55,16 @@ class ProtocolParserGenerator( "operation" to RuntimeType.operationModule(codegenContext.runtimeConfig), "Bytes" to RuntimeType.Bytes, "SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig), - // TODO(enableNewSmithyRuntimeCleanup): Remove the `PropertyBag` below - "PropertyBag" to RuntimeType.smithyHttp(codegenContext.runtimeConfig).resolve("property_bag::PropertyBag"), ) fun parseResponseFn( operationShape: OperationShape, - // TODO(enableNewSmithyRuntimeCleanup): Remove the `propertyBagAvailable` flag as if it were always set to `false` when switching to the orchestrator - propertyBagAvailable: Boolean, customizations: List, ): RuntimeType { val outputShape = operationShape.outputShape(model) val outputSymbol = symbolProvider.toSymbol(outputShape) val errorSymbol = symbolProvider.symbolForOperationError(operationShape) - val fnNameSuffix = if (propertyBagAvailable) "http_response_with_props" else "http_response" - return protocolFunctions.deserializeFn(operationShape, fnNameSuffix = fnNameSuffix) { fnName -> + return protocolFunctions.deserializeFn(operationShape, fnNameSuffix = "http_response") { fnName -> Attribute.AllowClippyUnnecessaryWraps.render(this) rustBlockTemplate( "pub fn $fnName(_response_status: u16, _response_headers: &#{http}::header::HeaderMap, _response_body: &[u8]) -> std::result::Result<#{O}, #{E}>", @@ -83,7 +78,6 @@ class ProtocolParserGenerator( outputShape, httpBindingResolver.responseBindings(operationShape), errorSymbol, - propertyBagAvailable, customizations, ) } @@ -153,7 +147,6 @@ class ProtocolParserGenerator( errorShape, httpBindingResolver.errorResponseBindings(errorShape), errorSymbol, - false, listOf( object : OperationCustomization() { override fun section(section: OperationSection): Writable = { @@ -189,24 +182,15 @@ class ProtocolParserGenerator( fun parseStreamingResponseFn( operationShape: OperationShape, - // TODO(enableNewSmithyRuntimeCleanup): Remove the `propertyBagAvailable` flag as if it were always set to `false` when switching to the orchestrator - propertyBagAvailable: Boolean, customizations: List, ): RuntimeType { val outputShape = operationShape.outputShape(model) val outputSymbol = symbolProvider.toSymbol(outputShape) val errorSymbol = symbolProvider.symbolForOperationError(operationShape) - val fnNameSuffix = if (propertyBagAvailable) "http_response_with_props" else "http_response" - return protocolFunctions.deserializeFn(operationShape, fnNameSuffix = fnNameSuffix) { fnName -> + return protocolFunctions.deserializeFn(operationShape, fnNameSuffix = "http_response") { fnName -> Attribute.AllowClippyUnnecessaryWraps.render(this) - val propertiesArg = if (propertyBagAvailable) { - Attribute.AllowUnusedVariables.render(this) - ", properties: &#{PropertyBag}" - } else { - "" - } rustBlockTemplate( - "pub fn $fnName(response: &mut #{http}::Response<#{SdkBody}>$propertiesArg) -> std::result::Result<#{O}, #{E}>", + "pub fn $fnName(response: &mut #{http}::Response<#{SdkBody}>) -> std::result::Result<#{O}, #{E}>", *codegenScope, "O" to outputSymbol, "E" to errorSymbol, @@ -228,7 +212,6 @@ class ProtocolParserGenerator( outputShape, httpBindingResolver.responseBindings(operationShape), errorSymbol, - propertyBagAvailable, customizations, ) } @@ -241,8 +224,6 @@ class ProtocolParserGenerator( outputShape: StructureShape, bindings: List, errorSymbol: Symbol, - // TODO(enableNewSmithyRuntimeCleanup): Remove the `propertyBagAvailable` flag as if it were always set to `false` when switching to the orchestrator - propertyBagAvailable: Boolean, customizations: List, ) { val httpBindingGenerator = ResponseBindingGenerator(protocol, codegenContext, operationShape) @@ -284,7 +265,7 @@ class ProtocolParserGenerator( writeCustomizations( customizations, - OperationSection.MutateOutput(customizations, operationShape, "_response_headers", propertyBagAvailable), + OperationSection.MutateOutput(customizations, operationShape, "_response_headers"), ) rust("output.build()$err") diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt index 34a6c7b1f0..e7ccd10507 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.model.shapes.DoubleShape import software.amazon.smithy.model.shapes.FloatShape import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.model.traits.EndpointTrait import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.protocoltests.traits.AppliesTo import software.amazon.smithy.protocoltests.traits.HttpMessageTestCase @@ -20,8 +21,8 @@ import software.amazon.smithy.protocoltests.traits.HttpResponseTestCase import software.amazon.smithy.protocoltests.traits.HttpResponseTestsTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule -import software.amazon.smithy.rust.codegen.client.smithy.customizations.EndpointPrefixGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.ClientInstantiator +import software.amazon.smithy.rust.codegen.client.smithy.generators.EndpointTraitBindings import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.allow import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency @@ -233,7 +234,16 @@ class DefaultProtocolTestGenerator( // https://github.com/awslabs/smithy/blob/be68f3bbdfe5bf50a104b387094d40c8069f16b1/smithy-aws-protocol-tests/model/restJson1/endpoint-paths.smithy#L19 host.orNull()?.also { host -> val withScheme = "http://$host" - when (val bindings = EndpointPrefixGenerator.endpointTraitBindings(codegenContext, operationShape)) { + val bindings = operationShape.getTrait(EndpointTrait::class.java).map { epTrait -> + EndpointTraitBindings( + codegenContext.model, + codegenContext.symbolProvider, + codegenContext.runtimeConfig, + operationShape, + epTrait, + ) + }.orNull() + when (bindings) { null -> rust("let endpoint_prefix = None;") else -> { withBlock("let input = ", ";") { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt index 66b9d7e722..690ad5b40f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt @@ -10,7 +10,6 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.generators.http.RequestBindingGenerator -import software.amazon.smithy.rust.codegen.client.smithy.protocols.ClientAdditionalPayloadContext import software.amazon.smithy.rust.codegen.core.rustlang.InlineDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -88,12 +87,7 @@ class RequestSerializerGenerator( "generate_body" to writable { if (bodyGenerator != null) { val body = writable { - bodyGenerator.generatePayload( - this, - "input", - operationShape, - ClientAdditionalPayloadContext(propertyBagAvailable = false), - ) + bodyGenerator.generatePayload(this, "input", operationShape) } val streamingMember = inputShape.findStreamingMember(codegenContext.model) val isBlobStreaming = diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt index accd436e42..0f68a27603 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt @@ -104,7 +104,7 @@ class ResponseDeserializerGenerator( } """, *codegenScope, - "parse_streaming_response" to parserGenerator.parseStreamingResponseFn(operationShape, false, customizations), + "parse_streaming_response" to parserGenerator.parseStreamingResponseFn(operationShape, customizations), "BeforeParseResponse" to writable { writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response")) }, @@ -146,7 +146,7 @@ class ResponseDeserializerGenerator( """, *codegenScope, "parse_error" to parserGenerator.parseErrorFn(operationShape, customizations), - "parse_response" to parserGenerator.parseResponseFn(operationShape, false, customizations), + "parse_response" to parserGenerator.parseResponseFn(operationShape, customizations), "BeforeParseResponse" to writable { writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response")) }, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt index 7c949c92a2..cb9c7db7e5 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt @@ -60,7 +60,7 @@ private val CLIENT_PROTOCOL_SUPPORT = ProtocolSupport( ) private class ClientAwsJsonFactory(private val version: AwsJsonVersion) : - ProtocolGeneratorFactory { + ProtocolGeneratorFactory { override fun protocol(codegenContext: ClientCodegenContext): Protocol = if (compatibleWithAwsQuery(codegenContext.serviceShape, version)) { AwsQueryCompatible(codegenContext, AwsJson(codegenContext, version)) @@ -68,8 +68,8 @@ private class ClientAwsJsonFactory(private val version: AwsJsonVersion) : AwsJson(codegenContext, version) } - override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): HttpBoundProtocolGenerator = - HttpBoundProtocolGenerator(codegenContext, protocol(codegenContext)) + override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator = + OperationGenerator(codegenContext, protocol(codegenContext)) override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT @@ -77,40 +77,40 @@ private class ClientAwsJsonFactory(private val version: AwsJsonVersion) : serviceShape.hasTrait() && version == AwsJsonVersion.Json10 } -private class ClientAwsQueryFactory : ProtocolGeneratorFactory { +private class ClientAwsQueryFactory : ProtocolGeneratorFactory { override fun protocol(codegenContext: ClientCodegenContext): Protocol = AwsQueryProtocol(codegenContext) - override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): HttpBoundProtocolGenerator = - HttpBoundProtocolGenerator(codegenContext, protocol(codegenContext)) + override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator = + OperationGenerator(codegenContext, protocol(codegenContext)) override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT } -private class ClientRestJsonFactory : ProtocolGeneratorFactory { +private class ClientRestJsonFactory : ProtocolGeneratorFactory { override fun protocol(codegenContext: ClientCodegenContext): Protocol = RestJson(codegenContext) - override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): HttpBoundProtocolGenerator = - HttpBoundProtocolGenerator(codegenContext, RestJson(codegenContext)) + override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator = + OperationGenerator(codegenContext, RestJson(codegenContext)) override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT } -private class ClientEc2QueryFactory : ProtocolGeneratorFactory { +private class ClientEc2QueryFactory : ProtocolGeneratorFactory { override fun protocol(codegenContext: ClientCodegenContext): Protocol = Ec2QueryProtocol(codegenContext) - override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): HttpBoundProtocolGenerator = - HttpBoundProtocolGenerator(codegenContext, protocol(codegenContext)) + override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator = + OperationGenerator(codegenContext, protocol(codegenContext)) override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT } class ClientRestXmlFactory( private val generator: (CodegenContext) -> Protocol = { RestXml(it) }, -) : ProtocolGeneratorFactory { +) : ProtocolGeneratorFactory { override fun protocol(codegenContext: ClientCodegenContext): Protocol = generator(codegenContext) - override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): HttpBoundProtocolGenerator = - HttpBoundProtocolGenerator(codegenContext, protocol(codegenContext)) + override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator = + OperationGenerator(codegenContext, protocol(codegenContext)) override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt index d8c8bf9dc2..1f60c251ac 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt @@ -5,57 +5,14 @@ package software.amazon.smithy.rust.codegen.client.smithy.protocols -import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationGenerator -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection -import software.amazon.smithy.rust.codegen.client.smithy.generators.SensitiveIndex -import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.MakeOperationGenerator -import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ProtocolParserGenerator -import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope -import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations import software.amazon.smithy.rust.codegen.core.smithy.generators.http.HttpMessageType -import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.AdditionalPayloadContext import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolPayloadGenerator import software.amazon.smithy.rust.codegen.core.smithy.protocols.HttpBoundProtocolPayloadGenerator import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.ProtocolFunctions -import software.amazon.smithy.rust.codegen.core.util.hasStreamingMember -import software.amazon.smithy.rust.codegen.core.util.outputShape - -// TODO(enableNewSmithyRuntimeCleanup): Delete this class when cleaning up `enableNewSmithyRuntime` (replace with ClientProtocolGenerator) -class HttpBoundProtocolGenerator( - codegenContext: ClientCodegenContext, - protocol: Protocol, - bodyGenerator: ProtocolPayloadGenerator = ClientHttpBoundProtocolPayloadGenerator(codegenContext, protocol), -) : OperationGenerator( - codegenContext, - protocol, - MakeOperationGenerator( - codegenContext, - protocol, - bodyGenerator, - public = true, - includeDefaultPayloadHeaders = true, - ), - bodyGenerator, - HttpBoundProtocolTraitImplGenerator(codegenContext, protocol), -) - -// TODO(enableNewSmithyRuntimeCleanup): Completely delete `AdditionalPayloadContext` when switching to the orchestrator -data class ClientAdditionalPayloadContext( - val propertyBagAvailable: Boolean, -) : AdditionalPayloadContext class ClientHttpBoundProtocolPayloadGenerator( codegenContext: ClientCodegenContext, @@ -63,14 +20,13 @@ class ClientHttpBoundProtocolPayloadGenerator( ) : ProtocolPayloadGenerator by HttpBoundProtocolPayloadGenerator( codegenContext, protocol, HttpMessageType.REQUEST, renderEventStreamBody = { writer, params -> - val propertyBagAvailable = (params.additionalPayloadContext as ClientAdditionalPayloadContext).propertyBagAvailable writer.rustTemplate( """ { let error_marshaller = #{errorMarshallerConstructorFn}(); let marshaller = #{marshallerConstructorFn}(); let (signer, signer_sender) = #{DeferredSigner}::new(); - #{insert_into_config} + _cfg.interceptor_state().store_put(signer_sender); let adapter: #{aws_smithy_http}::event_stream::MessageStreamAdapter<_, _> = ${params.outerName}.${params.memberName}.into_body_stream(marshaller, error_marshaller, signer); let body: #{SdkBody} = #{hyper}::Body::wrap_stream(adapter).into(); @@ -83,169 +39,6 @@ class ClientHttpBoundProtocolPayloadGenerator( "DeferredSigner" to RuntimeType.smithyEventStream(codegenContext.runtimeConfig).resolve("frame::DeferredSigner"), "marshallerConstructorFn" to params.marshallerConstructorFn, "errorMarshallerConstructorFn" to params.errorMarshallerConstructorFn, - "insert_into_config" to writable { - if (propertyBagAvailable) { - rust("properties.acquire_mut().insert(signer_sender);") - } else { - rust("_cfg.interceptor_state().store_put(signer_sender);") - } - }, ) }, ) - -// TODO(enableNewSmithyRuntimeCleanup): Delete this class when cleaning up `enableNewSmithyRuntime` -open class HttpBoundProtocolTraitImplGenerator( - codegenContext: ClientCodegenContext, - protocol: Protocol, -) { - private val symbolProvider = codegenContext.symbolProvider - private val model = codegenContext.model - private val runtimeConfig = codegenContext.runtimeConfig - private val httpBindingResolver = protocol.httpBindingResolver - private val protocolFunctions = ProtocolFunctions(codegenContext) - private val parserGenerator = ProtocolParserGenerator(codegenContext, protocol) - - private val codegenScope = arrayOf( - *preludeScope, - "ParseStrict" to RuntimeType.parseStrictResponse(runtimeConfig), - "ParseResponse" to RuntimeType.parseHttpResponse(runtimeConfig), - "http" to RuntimeType.Http, - "operation" to RuntimeType.operationModule(runtimeConfig), - "Bytes" to RuntimeType.Bytes, - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - ) - - private val sensitiveIndex = SensitiveIndex.of(model) - - open fun generateTraitImpls( - operationWriter: RustWriter, - operationShape: OperationShape, - customizations: List, - ) { - val outputSymbol = symbolProvider.toSymbol(operationShape.outputShape(model)) - val operationName = symbolProvider.toSymbol(operationShape).name - - // For streaming response bodies, we need to generate a different implementation of the parse traits. - // These will first offer the streaming input to the parser & potentially read the body into memory - // if an error occurred or if the streaming parser indicates that it needs the full data to proceed. - val streaming = operationShape.outputShape(model).hasStreamingMember(model) - if (streaming) { - operationWriter.renderStreamingTraits(operationName, outputSymbol, operationShape, customizations) - } else { - operationWriter.renderNonStreamingTraits(operationName, outputSymbol, operationShape, customizations) - } - } - - private fun RustWriter.renderNonStreamingTraits( - operationName: String?, - outputSymbol: Symbol, - operationShape: OperationShape, - customizations: List, - ) { - val successCode = httpBindingResolver.httpTrait(operationShape).code - val localScope = arrayOf( - "O" to outputSymbol, - "E" to symbolProvider.symbolForOperationError(operationShape), - "parse_error" to parserGenerator.parseErrorFn(operationShape, customizations), - "parse_response" to parserGenerator.parseResponseFn(operationShape, true, customizations), - "BeforeParseResponse" to writable { - writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response")) - }, - ) - val sensitive = writable { - if (sensitiveIndex.hasSensitiveOutput(operationShape)) { - rust("fn sensitive(&self) -> bool { true }") - } - } - rustTemplate( - """ - impl #{ParseStrict} for $operationName { - type Output = #{Result}<#{O}, #{E}>; - fn parse(&self, response: &#{http}::Response<#{Bytes}>) -> Self::Output { - let (success, status) = (response.status().is_success(), response.status().as_u16()); - let headers = response.headers(); - let body = response.body().as_ref(); - #{BeforeParseResponse} - if !success && status != $successCode { - #{parse_error}(status, headers, body) - } else { - #{parse_response}(status, headers, body) - } - } - #{sensitive} - }""", - *codegenScope, - *localScope, - "sensitive" to sensitive, - ) - } - - private fun RustWriter.renderStreamingTraits( - operationName: String, - outputSymbol: Symbol, - operationShape: OperationShape, - customizations: List, - ) { - val successCode = httpBindingResolver.httpTrait(operationShape).code - rustTemplate( - """ - impl #{ParseResponse} for $operationName { - type Output = #{Result}<#{O}, #{E}>; - fn parse_unloaded(&self, response: &mut #{operation}::Response) -> #{Option} { - #{BeforeParseResponse} - // This is an error, defer to the non-streaming parser - if !response.http().status().is_success() && response.http().status().as_u16() != $successCode { - return #{None}; - } - #{Some}(#{parse_streaming_response}(response)) - } - fn parse_loaded(&self, response: &#{http}::Response<#{Bytes}>) -> Self::Output { - // if streaming, we only hit this case if its an error - #{parse_error}(response.status().as_u16(), response.headers(), response.body().as_ref()) - } - } - """, - "O" to outputSymbol, - "E" to symbolProvider.symbolForOperationError(operationShape), - "parse_streaming_response" to parseStreamingResponse(operationShape, customizations), - "parse_error" to parserGenerator.parseErrorFn(operationShape, customizations), - "BeforeParseResponse" to writable { - writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response")) - }, - *codegenScope, - ) - } - - private fun parseStreamingResponse( - operationShape: OperationShape, - customizations: List, - ): RuntimeType { - val outputShape = operationShape.outputShape(model) - val outputSymbol = symbolProvider.toSymbol(outputShape) - val errorSymbol = symbolProvider.symbolForOperationError(operationShape) - return protocolFunctions.deserializeFn(operationShape, fnNameSuffix = "op_response") { fnName -> - Attribute.AllowClippyUnnecessaryWraps.render(this) - rustBlockTemplate( - "pub fn $fnName(op_response: &mut #{operation}::Response) -> #{Result}<#{O}, #{E}>", - *codegenScope, - "O" to outputSymbol, - "E" to errorSymbol, - ) { - // Not all implementations will use the property bag, but some will - Attribute.AllowUnusedVariables.render(this) - rust("let (response, properties) = op_response.parts_mut();") - rustTemplate( - """ - #{parse_streaming_response}(response, &properties) - """, - "parse_streaming_response" to parserGenerator.parseStreamingResponseFn( - operationShape, - true, - customizations, - ), - ) - } - } - } -} diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt index 29f25e98af..e53b66fc14 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt @@ -6,7 +6,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.customizations import org.junit.jupiter.api.Test -import software.amazon.smithy.rust.codegen.client.testutil.TestCodegenSettings import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency @@ -26,10 +25,7 @@ class HttpAuthDecoratorTest { @Test fun multipleAuthSchemesSchemeSelection() { - clientIntegrationTest( - TestModels.allSchemes, - TestCodegenSettings.orchestratorModeTestParams, - ) { codegenContext, rustCrate -> + clientIntegrationTest(TestModels.allSchemes) { codegenContext, rustCrate -> rustCrate.integrationTest("tests") { val moduleName = codegenContext.moduleUseName() Attribute.TokioTest.render(this) @@ -51,11 +47,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await @@ -85,11 +77,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await @@ -105,10 +93,7 @@ class HttpAuthDecoratorTest { @Test fun apiKeyInQueryString() { - clientIntegrationTest( - TestModels.apiKeyInQueryString, - TestCodegenSettings.orchestratorModeTestParams, - ) { codegenContext, rustCrate -> + clientIntegrationTest(TestModels.apiKeyInQueryString) { codegenContext, rustCrate -> rustCrate.integrationTest("api_key_applied_to_query_string") { val moduleName = codegenContext.moduleUseName() Attribute.TokioTest.render(this) @@ -130,11 +115,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await @@ -150,10 +131,7 @@ class HttpAuthDecoratorTest { @Test fun apiKeyInHeaders() { - clientIntegrationTest( - TestModels.apiKeyInHeaders, - TestCodegenSettings.orchestratorModeTestParams, - ) { codegenContext, rustCrate -> + clientIntegrationTest(TestModels.apiKeyInHeaders) { codegenContext, rustCrate -> rustCrate.integrationTest("api_key_applied_to_headers") { val moduleName = codegenContext.moduleUseName() Attribute.TokioTest.render(this) @@ -176,11 +154,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await @@ -196,10 +170,7 @@ class HttpAuthDecoratorTest { @Test fun basicAuth() { - clientIntegrationTest( - TestModels.basicAuth, - TestCodegenSettings.orchestratorModeTestParams, - ) { codegenContext, rustCrate -> + clientIntegrationTest(TestModels.basicAuth) { codegenContext, rustCrate -> rustCrate.integrationTest("basic_auth") { val moduleName = codegenContext.moduleUseName() Attribute.TokioTest.render(this) @@ -222,11 +193,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await @@ -242,10 +209,7 @@ class HttpAuthDecoratorTest { @Test fun bearerAuth() { - clientIntegrationTest( - TestModels.bearerAuth, - TestCodegenSettings.orchestratorModeTestParams, - ) { codegenContext, rustCrate -> + clientIntegrationTest(TestModels.bearerAuth) { codegenContext, rustCrate -> rustCrate.integrationTest("bearer_auth") { val moduleName = codegenContext.moduleUseName() Attribute.TokioTest.render(this) @@ -268,11 +232,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await @@ -288,10 +248,7 @@ class HttpAuthDecoratorTest { @Test fun optionalAuth() { - clientIntegrationTest( - TestModels.optionalAuth, - TestCodegenSettings.orchestratorModeTestParams, - ) { codegenContext, rustCrate -> + clientIntegrationTest(TestModels.optionalAuth) { codegenContext, rustCrate -> rustCrate.integrationTest("optional_auth") { val moduleName = codegenContext.moduleUseName() Attribute.TokioTest.render(this) @@ -310,11 +267,7 @@ class HttpAuthDecoratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let _ = client.some_operation() .send() .await diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt index 3463ab1e73..1bcc30e0c3 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt @@ -6,13 +6,11 @@ package software.amazon.smithy.rust.codegen.client.smithy.customizations import org.junit.jupiter.api.Test -import software.amazon.smithy.rust.codegen.client.testutil.TestCodegenSettings import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope -import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.testModule import software.amazon.smithy.rust.codegen.core.testutil.tokioTest @@ -35,10 +33,7 @@ class MetadataCustomizationTest { @Test fun `extract metadata via customizable operation`() { - clientIntegrationTest( - model, - params = IntegrationTestParams(additionalSettings = TestCodegenSettings.orchestratorMode()), - ) { clientCodegenContext, rustCrate -> + clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig val codegenScope = arrayOf( *preludeScope, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt index 48821e380d..671f622497 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt @@ -6,14 +6,12 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators import org.junit.jupiter.api.Test -import software.amazon.smithy.rust.codegen.client.testutil.TestCodegenSettings import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency.Companion.smithyRuntimeApiTestUtil import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope -import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.testModule import software.amazon.smithy.rust.codegen.core.testutil.tokioTest @@ -39,10 +37,7 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { @Test fun `operation overrides endpoint resolver`() { - clientIntegrationTest( - model, - params = IntegrationTestParams(additionalSettings = TestCodegenSettings.orchestratorMode()), - ) { clientCodegenContext, rustCrate -> + clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig val codegenScope = arrayOf( *preludeScope, @@ -85,10 +80,7 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { @Test fun `operation overrides http connector`() { - clientIntegrationTest( - model, - params = IntegrationTestParams(additionalSettings = TestCodegenSettings.orchestratorMode()), - ) { clientCodegenContext, rustCrate -> + clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig val codegenScope = arrayOf( *preludeScope, @@ -163,10 +155,7 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { @Test fun `operation overrides retry strategy`() { - clientIntegrationTest( - model, - params = IntegrationTestParams(additionalSettings = TestCodegenSettings.orchestratorMode()), - ) { clientCodegenContext, rustCrate -> + clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig val codegenScope = arrayOf( *preludeScope, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt index 0726c6870c..4b3d7f3a5f 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt @@ -6,11 +6,9 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators import org.junit.jupiter.api.Test -import software.amazon.smithy.rust.codegen.client.testutil.TestCodegenSettings import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest @@ -71,23 +69,9 @@ internal class PaginatorGeneratorTest { } """.asSmithyModel() - // TODO(enableNewSmithyRuntimeCleanup): Remove this middleware test when launching - @Test - fun `generate paginators that compile with middleware`() { - clientIntegrationTest(model) { clientCodegenContext, rustCrate -> - rustCrate.integrationTest("paginators_generated") { - Attribute.AllowUnusedImports.render(this) - rust("use ${clientCodegenContext.moduleUseName()}::operation::paginated_list::paginator::PaginatedListPaginator;") - } - } - } - @Test fun `generate paginators that compile`() { - clientIntegrationTest( - model, - params = IntegrationTestParams(additionalSettings = TestCodegenSettings.orchestratorMode()), - ) { clientCodegenContext, rustCrate -> + clientIntegrationTest(model) { clientCodegenContext, rustCrate -> rustCrate.integrationTest("paginators_generated") { Attribute.AllowUnusedImports.render(this) rust("use ${clientCodegenContext.moduleUseName()}::operation::paginated_list::paginator::PaginatedListPaginator;") diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt index 3da4f1656e..121b1fd6a5 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt @@ -8,14 +8,11 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators.client import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.MemberShape -import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.testutil.TestCodegenSettings import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest import software.amazon.smithy.rust.codegen.core.util.lookup @@ -71,7 +68,7 @@ class FluentClientGeneratorTest { @Test fun `send() future implements Send`() { - val test: (ClientCodegenContext, RustCrate) -> Unit = { codegenContext, rustCrate -> + clientIntegrationTest(model) { codegenContext, rustCrate -> rustCrate.integrationTest("send_future_is_send") { val moduleName = codegenContext.moduleUseName() rustTemplate( @@ -85,33 +82,25 @@ class FluentClientGeneratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); check_send(client.say_hello().send()); } """, - "TestConnection" to CargoDependency.smithyClient(codegenContext.runtimeConfig) + "TestConnection" to software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency.smithyClient( + codegenContext.runtimeConfig, + ) .toDevDependency() .withFeature("test-util").toType() .resolve("test_connection::TestConnection"), - "SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig), + "SdkBody" to software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.sdkBody(codegenContext.runtimeConfig), ) } } - clientIntegrationTest(model, TestCodegenSettings.middlewareModeTestParams, test = test) - clientIntegrationTest( - model, - TestCodegenSettings.orchestratorModeTestParams, - test = test, - ) } @Test fun `generate inner builders`() { - val test: (ClientCodegenContext, RustCrate) -> Unit = { codegenContext, rustCrate -> + clientIntegrationTest(model) { codegenContext, rustCrate -> rustCrate.integrationTest("inner_builder") { val moduleName = codegenContext.moduleUseName() rustTemplate( @@ -123,11 +112,7 @@ class FluentClientGeneratorTest { .endpoint_resolver("http://localhost:1234") .http_connector(connector.clone()) .build(); - let smithy_client = aws_smithy_client::Builder::new() - .connector(connector.clone()) - .middleware_fn(|r| r) - .build_dyn(); - let client = $moduleName::Client::with_config(smithy_client, config); + let client = $moduleName::Client::from_conf(config); let say_hello_fluent_builder = client.say_hello().byte_value(4).foo("hello!"); assert_eq!(*say_hello_fluent_builder.get_foo(), Some("hello!".to_string())); @@ -143,11 +128,5 @@ class FluentClientGeneratorTest { ) } } - clientIntegrationTest(model, TestCodegenSettings.middlewareModeTestParams, test = test) - clientIntegrationTest( - model, - TestCodegenSettings.orchestratorModeTestParams, - test = test, - ) } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorMiddlewareTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorMiddlewareTest.kt deleted file mode 100644 index 3346245088..0000000000 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorMiddlewareTest.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.client.smithy.generators.protocol - -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization -import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationGenerator -import software.amazon.smithy.rust.codegen.client.smithy.protocols.HttpBoundProtocolTraitImplGenerator -import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.rustlang.escape -import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate -import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.AdditionalPayloadContext -import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolPayloadGenerator -import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport -import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol -import software.amazon.smithy.rust.codegen.core.smithy.protocols.ProtocolGeneratorFactory -import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson -import software.amazon.smithy.rust.codegen.core.util.outputShape - -private class TestProtocolPayloadGenerator(private val body: String) : ProtocolPayloadGenerator { - override fun payloadMetadata(operationShape: OperationShape, additionalPayloadContext: AdditionalPayloadContext) = - ProtocolPayloadGenerator.PayloadMetadata(takesOwnership = false) - - override fun generatePayload( - writer: RustWriter, - shapeName: String, - operationShape: OperationShape, - additionalPayloadContext: AdditionalPayloadContext, - ) { - writer.writeWithNoFormatting(body) - } -} - -private class TestProtocolTraitImplGenerator( - private val codegenContext: ClientCodegenContext, - private val correctResponse: String, -) : HttpBoundProtocolTraitImplGenerator(codegenContext, RestJson(codegenContext)) { - private val symbolProvider = codegenContext.symbolProvider - - override fun generateTraitImpls( - operationWriter: RustWriter, - operationShape: OperationShape, - customizations: List, - ) { - operationWriter.rustTemplate( - """ - impl #{parse_strict} for ${operationShape.id.name}{ - type Output = Result<#{Output}, #{Error}>; - fn parse(&self, _response: &#{Response}<#{Bytes}>) -> Self::Output { - ${operationWriter.escape(correctResponse)} - } - } - """, - "parse_strict" to RuntimeType.parseStrictResponse(codegenContext.runtimeConfig), - "Output" to symbolProvider.toSymbol(operationShape.outputShape(codegenContext.model)), - "Error" to symbolProvider.symbolForOperationError(operationShape), - "Response" to RuntimeType.HttpResponse, - "Bytes" to RuntimeType.Bytes, - ) - } -} - -private class TestProtocolMakeOperationGenerator( - codegenContext: CodegenContext, - protocol: Protocol, - body: String, - private val httpRequestBuilder: String, -) : MakeOperationGenerator( - codegenContext, - protocol, - TestProtocolPayloadGenerator(body), - public = true, - includeDefaultPayloadHeaders = true, -) { - override fun createHttpRequest(writer: RustWriter, operationShape: OperationShape) { - writer.rust("#T::new()", RuntimeType.HttpRequestBuilder) - writer.writeWithNoFormatting(httpRequestBuilder) - } -} - -// A stubbed test protocol to do enable testing intentionally broken protocols -private class TestProtocolGenerator( - codegenContext: ClientCodegenContext, - protocol: Protocol, - httpRequestBuilder: String, - body: String, - correctResponse: String, -) : OperationGenerator( - codegenContext, - protocol, - TestProtocolMakeOperationGenerator(codegenContext, protocol, body, httpRequestBuilder), - TestProtocolPayloadGenerator(body), - TestProtocolTraitImplGenerator(codegenContext, correctResponse), -) - -private class TestProtocolFactory( - private val httpRequestBuilder: String, - private val body: String, - private val correctResponse: String, -) : ProtocolGeneratorFactory { - override fun protocol(codegenContext: ClientCodegenContext): Protocol = RestJson(codegenContext) - - override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator { - return TestProtocolGenerator( - codegenContext, - protocol(codegenContext), - httpRequestBuilder, - body, - correctResponse, - ) - } - - override fun support(): ProtocolSupport { - return ProtocolSupport( - requestSerialization = true, - requestBodySerialization = true, - responseDeserialization = true, - errorDeserialization = true, - requestDeserialization = false, - requestBodyDeserialization = false, - responseSerialization = false, - errorSerialization = false, - ) - } -} diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestCodegenSettings.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestCodegenSettings.kt deleted file mode 100644 index a54397ff59..0000000000 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestCodegenSettings.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.client.testutil - -import software.amazon.smithy.model.node.ObjectNode -import software.amazon.smithy.model.node.StringNode -import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams - -object TestCodegenSettings { - // TODO(enableNewSmithyRuntimeCleanup): Delete this when removing `enableNewSmithyRuntime` feature gate - fun middlewareMode(): ObjectNode = ObjectNode.objectNodeBuilder() - .withMember( - "codegen", - ObjectNode.objectNodeBuilder() - .withMember("enableNewSmithyRuntime", StringNode.from("middleware")).build(), - ) - .build() - - // TODO(enableNewSmithyRuntimeCleanup): Delete this when removing `enableNewSmithyRuntime` feature gate - fun orchestratorMode(): ObjectNode = ObjectNode.objectNodeBuilder() - .withMember( - "codegen", - ObjectNode.objectNodeBuilder() - .withMember("enableNewSmithyRuntime", StringNode.from("orchestrator")).build(), - ) - .build() - - // TODO(enableNewSmithyRuntimeCleanup): Delete this when removing `enableNewSmithyRuntime` feature gate - val middlewareModeTestParams get(): IntegrationTestParams = - IntegrationTestParams(additionalSettings = middlewareMode()) - - // TODO(enableNewSmithyRuntimeCleanup): Delete this when removing `enableNewSmithyRuntime` feature gate - val orchestratorModeTestParams get(): IntegrationTestParams = - IntegrationTestParams(additionalSettings = orchestratorMode()) -}