From 4e1db7047ef4766060a3b272af403c3a411f19e1 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 5 Jan 2021 09:58:52 -0500 Subject: [PATCH 01/50] Move AWS specific generation into its own folder --- .github/workflows/ci.yaml | 8 +- aws-sdk-codegen/build.gradle.kts | 92 ------------------- .../smithy/rustsdk/AwsCodegenDecorator.kt | 21 ----- .../amazon/smithy/rustsdk/BaseAwsConfig.kt | 34 ------- ...y.rust.codegen.smithy.RustCodegenDecorator | 1 - {aws-sdk => aws/sdk}/.gitignore | 0 {aws-sdk => aws/sdk}/README.md | 6 +- {aws-sdk => aws/sdk}/build.gradle.kts | 12 +-- {aws-sdk => aws/sdk}/models/dynamodb.json | 0 settings.gradle.kts | 4 +- 10 files changed, 15 insertions(+), 163 deletions(-) delete mode 100644 aws-sdk-codegen/build.gradle.kts delete mode 100644 aws-sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt delete mode 100644 aws-sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseAwsConfig.kt delete mode 100644 aws-sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator rename {aws-sdk => aws/sdk}/.gitignore (100%) rename {aws-sdk => aws/sdk}/README.md (73%) rename {aws-sdk => aws/sdk}/build.gradle.kts (94%) rename {aws-sdk => aws/sdk}/models/dynamodb.json (100%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6ccf547fd0..12f0e6a1c5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -143,10 +143,10 @@ jobs: with: java-version: ${{ env.java_version }} - name: Generate the SDK - run: ./gradlew :aws-sdk:assemble + run: ./gradlew :aws:sdk:assemble # docs are not included in the artifact; this step validates that they can be generated - name: Generate docs - run: ./gradlew :aws-sdk:cargoDocs + run: ./gradlew :aws:sdk:cargoDocs - name: Get current date id: date run: echo "name=${GITHUB_REF##*/}-$(date +'%Y-%m-%d')" >> $GITHUB_ENV @@ -157,5 +157,5 @@ jobs: with: name: aws-sdk-${{ env.name }}-${{ github.sha }} path: | - aws-sdk/build/aws-sdk/ - !aws-sdk/build/aws-sdk/target + aws/sdk/build/aws-sdk/ + !aws/sdk/build/aws-sdk/target diff --git a/aws-sdk-codegen/build.gradle.kts b/aws-sdk-codegen/build.gradle.kts deleted file mode 100644 index 7c7673f1a6..0000000000 --- a/aws-sdk-codegen/build.gradle.kts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ -plugins { - kotlin("jvm") - jacoco - maven - `maven-publish` -} - -description = "AWS Specific Customizations for Smithy code generation" -extra["displayName"] = "Smithy :: Rust :: AWS Codegen" -extra["moduleName"] = "software.amazon.smithy.rustsdk" - -group = "software.amazon.software.amazon.smithy.rust.codegen.smithy" -version = "0.1.0" - -val smithyVersion: String by project - -dependencies { - implementation(project(":codegen")) - implementation("software.amazon.smithy:smithy-aws-protocol-tests:$smithyVersion") - implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") - implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") -} - -tasks.compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -tasks.compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -// Reusable license copySpec -val licenseSpec = copySpec { - from("${project.rootDir}/LICENSE") - from("${project.rootDir}/NOTICE") -} - -// Configure jars to include license related info -tasks.jar { - metaInf.with(licenseSpec) - inputs.property("moduleName", project.name) - manifest { - attributes["Automatic-Module-Name"] = project.name - } -} - -val sourcesJar by tasks.creating(Jar::class) { - group = "publishing" - description = "Assembles Kotlin sources jar" - classifier = "sources" - from(sourceSets.getByName("main").allSource) -} - -tasks.test { - useJUnitPlatform() - testLogging { - events("passed", "skipped", "failed") - showStandardStreams = true - } -} - - -// Configure jacoco (code coverage) to generate an HTML report -tasks.jacocoTestReport { - reports { - xml.isEnabled = false - csv.isEnabled = false - html.destination = file("$buildDir/reports/jacoco") - } -} - -// Always run the jacoco test report after testing. -tasks["test"].finalizedBy(tasks["jacocoTestReport"]) - - -publishing { - publications { - create("default") { - from(components["java"]) - artifact(sourcesJar) - } - } - repositories { - maven { - url = uri("$buildDir/repository") - } - } -} 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 deleted file mode 100644 index 9a1628e78f..0000000000 --- a/aws-sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt +++ /dev/null @@ -1,21 +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.rust.codegen.smithy.RustCodegenDecorator -import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig -import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization - -class AwsCodegenDecorator : RustCodegenDecorator { - override val name: String = "AwsSdkCodgenDecorator" - override val order: Byte = -1 - override fun configCustomizations( - protocolConfig: ProtocolConfig, - baseCustomizations: List - ): List { - return listOf(BaseAwsConfig()) + baseCustomizations - } -} diff --git a/aws-sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseAwsConfig.kt b/aws-sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseAwsConfig.kt deleted file mode 100644 index e81d5d52f1..0000000000 --- a/aws-sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseAwsConfig.kt +++ /dev/null @@ -1,34 +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.rust.codegen.rustlang.Attribute -import software.amazon.smithy.rust.codegen.rustlang.rust -import software.amazon.smithy.rust.codegen.rustlang.writable -import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization -import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig - -/** - * Just a Stub - * - * Augment the config object with the AWS-specific fields like service and region - */ -class BaseAwsConfig : ConfigCustomization() { - override fun section(section: ServiceConfig) = writable { - when (section) { - ServiceConfig.ConfigStruct -> { - Attribute.AllowUnused.render(this) - rust("pub(crate) region: String,") - } - ServiceConfig.BuilderBuild -> rust("region: \"todo\".to_owned(),") - else -> {} - /*ServiceConfig.ConfigImpl -> TODO() - ServiceConfig.BuilderStruct -> TODO() - ServiceConfig.BuilderImpl -> TODO() - ServiceConfig.BuilderBuild -> TODO()*/ - } - } -} diff --git a/aws-sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator b/aws-sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator deleted file mode 100644 index 1ceb403cac..0000000000 --- a/aws-sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator +++ /dev/null @@ -1 +0,0 @@ -software.amazon.smithy.rustsdk.AwsCodegenDecorator diff --git a/aws-sdk/.gitignore b/aws/sdk/.gitignore similarity index 100% rename from aws-sdk/.gitignore rename to aws/sdk/.gitignore diff --git a/aws-sdk/README.md b/aws/sdk/README.md similarity index 73% rename from aws-sdk/README.md rename to aws/sdk/README.md index 3f59810052..a46430ca32 100644 --- a/aws-sdk/README.md +++ b/aws/sdk/README.md @@ -1,13 +1,13 @@ # AWS SDK Generator -This directory contains a gradle project to generate an AWS SDK. It uses the Smithy Build Plugin combined with the customizations specified in `aws-sdk-codegen` to generate an AWS SDK from Smithy models. +This directory contains a gradle project to generate an AWS SDK. It uses the Smithy Build Plugin combined with the customizations specified in `aws/sdk-codegen` to generate an AWS SDK from Smithy models. `build.gradle.kts` will generate a `smithy-build.json` dynamically from all models in the `models` directory. ## Usage Generate an SDK: -`./gradlew :aws-sdk:assemble` +`./gradlew :aws:sdk:assemble` Generate, compile, and test an SDK: -`./gradlew :aws-sdk:build` +`./gradlew :aws:sdk:build` diff --git a/aws-sdk/build.gradle.kts b/aws/sdk/build.gradle.kts similarity index 94% rename from aws-sdk/build.gradle.kts rename to aws/sdk/build.gradle.kts index d4913a9254..3f7fadcf46 100644 --- a/aws-sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -31,7 +31,7 @@ buildscript { } dependencies { - implementation(project(":aws-sdk-codegen")) + implementation(project(":aws:sdk-codegen")) implementation("software.amazon.smithy:smithy-aws-protocol-tests:$smithyVersion") implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") @@ -96,7 +96,7 @@ task("relocateServices") { doLast { awsServices.forEach { copy { - from("$buildDir/smithyprojections/aws-sdk/${it.module}/rust-codegen") + from("$buildDir/smithyprojections/sdk/${it.module}/rust-codegen") into(sdkOutputDir.resolve(it.module)) } } @@ -139,7 +139,7 @@ tasks["assemble"].finalizedBy("finalizeSdk") tasks.register("cargoCheck") { - workingDir(buildDir.resolve("aws-sdk")) + workingDir(sdkOutputDir) // disallow warnings environment("RUSTFLAGS", "-D warnings") commandLine("cargo", "check") @@ -147,7 +147,7 @@ tasks.register("cargoCheck") { } tasks.register("cargoTest") { - workingDir(buildDir.resolve("aws-sdk")) + workingDir(sdkOutputDir) // disallow warnings environment("RUSTFLAGS", "-D warnings") commandLine("cargo", "test") @@ -155,7 +155,7 @@ tasks.register("cargoTest") { } tasks.register("cargoDocs") { - workingDir(buildDir.resolve("aws-sdk")) + workingDir(sdkOutputDir) // disallow warnings environment("RUSTFLAGS", "-D warnings") commandLine("cargo", "doc", "--no-deps") @@ -163,7 +163,7 @@ tasks.register("cargoDocs") { } tasks.register("cargoClippy") { - workingDir(buildDir.resolve("aws-sdk")) + workingDir(sdkOutputDir) // disallow warnings environment("RUSTFLAGS", "-D warnings") commandLine("cargo", "clippy") diff --git a/aws-sdk/models/dynamodb.json b/aws/sdk/models/dynamodb.json similarity index 100% rename from aws-sdk/models/dynamodb.json rename to aws/sdk/models/dynamodb.json diff --git a/settings.gradle.kts b/settings.gradle.kts index 5b403e8ca3..b8ae02580b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,5 +20,5 @@ enableFeaturePreview("GRADLE_METADATA") include(":codegen") include(":codegen-test") include(":rust-runtime") -include(":aws-sdk-codegen") -include(":aws-sdk") +include(":aws:sdk-codegen") +include(":aws:sdk") From 7d25fbaf1b7f54bc6b7b452e0b8d9037dd02e44d Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 5 Jan 2021 18:38:55 -0500 Subject: [PATCH 02/50] Initial Pass at an IO layer for the Rust SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review this and give your thoughts—over the coming weeks I'll be refactoring and pulling off individual pieces into separate PRs as I clean things up. --- aws/rust-runtime/auth/.gitignore | 2 + aws/rust-runtime/auth/Cargo.toml | 15 + aws/rust-runtime/auth/src/lib.rs | 320 +++++++++ aws/rust-runtime/operation/src/endpoint.rs | 106 +++ aws/rust-runtime/operation/src/middleware.rs | 262 +++++++ .../operation/src/signing_middleware.rs | 42 ++ aws/rust-runtime/test.sh | 18 + aws/sdk-codegen/build.gradle.kts | 92 +++ .../smithy/rustsdk/AwsCodegenDecorator.kt | 21 + .../rustsdk/CredentialProviderConfig.kt | 48 ++ ...y.rust.codegen.smithy.RustCodegenDecorator | 1 + aws/sdk/build.gradle.kts | 25 +- .../sdk}/dynamo-it/.gitignore | 0 .../sdk}/dynamo-it/Cargo.lock | 649 ++++++++++++++++-- aws/sdk/dynamo-it/Cargo.toml | 22 + .../sdk}/dynamo-it/docker-compose.yml | 0 aws/sdk/dynamo-it/src/main.rs | 153 +++++ codegen-test/dynamo-it/Cargo.toml | 14 - codegen-test/dynamo-it/src/main.rs | 97 --- .../rust/codegen/smithy/CodegenVisitor.kt | 7 +- .../codegen/smithy/RustCodegenDecorator.kt | 20 +- .../generators/HttpProtocolGenerator.kt | 29 +- .../smithy/generators/ServiceGenerator.kt | 8 +- .../config/IdempotencyProviderConfig.kt | 33 +- 24 files changed, 1780 insertions(+), 204 deletions(-) create mode 100644 aws/rust-runtime/auth/.gitignore create mode 100644 aws/rust-runtime/auth/Cargo.toml create mode 100644 aws/rust-runtime/auth/src/lib.rs create mode 100644 aws/rust-runtime/operation/src/endpoint.rs create mode 100644 aws/rust-runtime/operation/src/middleware.rs create mode 100644 aws/rust-runtime/operation/src/signing_middleware.rs create mode 100755 aws/rust-runtime/test.sh create mode 100644 aws/sdk-codegen/build.gradle.kts create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt create mode 100644 aws/sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator rename {codegen-test => aws/sdk}/dynamo-it/.gitignore (100%) rename {codegen-test => aws/sdk}/dynamo-it/Cargo.lock (67%) create mode 100644 aws/sdk/dynamo-it/Cargo.toml rename {codegen-test => aws/sdk}/dynamo-it/docker-compose.yml (100%) create mode 100644 aws/sdk/dynamo-it/src/main.rs delete mode 100644 codegen-test/dynamo-it/Cargo.toml delete mode 100644 codegen-test/dynamo-it/src/main.rs diff --git a/aws/rust-runtime/auth/.gitignore b/aws/rust-runtime/auth/.gitignore new file mode 100644 index 0000000000..2c96eb1b65 --- /dev/null +++ b/aws/rust-runtime/auth/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock diff --git a/aws/rust-runtime/auth/Cargo.toml b/aws/rust-runtime/auth/Cargo.toml new file mode 100644 index 0000000000..bcf53147d3 --- /dev/null +++ b/aws/rust-runtime/auth/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "auth" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" +description = "Authentication related functionality for the AWS Rust SDK. All interfaces considered unstable." + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +http = "0.2.2" +aws-sigv4 = { git = "https://github.com/rcoh/sigv4" } + +[dev-dependencies] +tokio = { version = "1", features = ["full"]} diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs new file mode 100644 index 0000000000..30a22d64db --- /dev/null +++ b/aws/rust-runtime/auth/src/lib.rs @@ -0,0 +1,320 @@ +use std::error::Error; +use std::future::Future; +use std::time::{Instant, SystemTime}; + +/// AWS SDK Credentials +/// +/// An opaque struct representing credentials that may be used in an AWS SDK, modeled on +/// the [CRT credentials implementation](https://github.com/awslabs/aws-c-auth/blob/main/source/credentials.c). +#[derive(Clone)] +pub struct Credentials { + // TODO: consider if these fields should be Arc'd; Credentials are cloned when + // retrieved from a credentials provider. + access_key_id: String, + secret_access_key: String, + session_token: Option, + + /// Credential Expiry + /// + /// A timepoint at which the credentials should no longer + /// be used because they have expired. The primary purpose of this value is to allow + /// credentials to communicate to the caching provider when they need to be refreshed. + /// + /// If these credentials never expire, this value will be set to `None` + /// + /// TODO: consider if `Instant` is the best representation—other options: + /// - SystemTime, we don't need monotonicity for this + /// - u64 + expiration: Option, +} + +impl Credentials { + /// Create a Credentials struct from static credentials + pub fn from_static( + access_key_id: T, + secret_access_key: T, + session_token: Option, + ) -> Self { + Credentials { + access_key_id: access_key_id.to_string(), + secret_access_key: secret_access_key.to_string(), + session_token: session_token.map(|tok| tok.to_string()), + expiration: None, + } + } +} + +/// An error retrieving credentials from a credentials provider +/// +/// TODO: consider possible explicit variants +#[derive(Debug)] +pub struct CredentialsProviderError { + cause: Box, +} + +impl Display for CredentialsProviderError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.cause.fmt(f) + } +} + +impl Error for CredentialsProviderError {} + +/// A `Future` that will resolve to Credentials or a credentials loading error +/// +/// This is returned by ProvideCredentials +#[must_use = "futures do nothing unless polled"] +pub struct CredentialsFuture { + inner: Pin> + Send>>, +} + +impl Future for CredentialsFuture { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { + Pin::new(&mut self.inner).poll(cx) + } +} + +impl CredentialsFuture { + pub fn ready(credentials: Credentials) -> Self { + let inner = Pin::new(Box::new(std::future::ready(Ok(credentials)))); + CredentialsFuture { inner } + } +} + +// TODO +type CredentialsError = Box; + +/// A credentials provider +/// +/// Credentials providers may be sync or async, they may cache credentials, etc. +/// +/// WARNING: This interface is unstable pending async traits +pub trait ProvideCredentials { + fn credentials(&self) -> Result; +} + +pub fn default_provider() -> impl ProvideCredentials { + // todo: this should be a chain, maybe CRT? + // Determine what the minimum support is + Credentials::from_static("todo", "todo", None) +} + +impl ProvideCredentials for Credentials { + fn credentials(&self) -> Result { + Ok(self.clone()) + } +} + +#[derive(Eq, PartialEq)] +pub enum SigningAlgorithm { + SigV4, +} + +#[derive(Eq, PartialEq)] +pub enum HttpSignatureType { + /// A signature for a full http request should be computed, with header updates applied to the signing result. + HttpRequestHeaders, + /// A signature for a full http request should be computed, with query param updates applied to the signing result. + HttpRequestQueryParams, +} + +pub enum SigningConfig { + Http(HttpSigningConfig), + // Http Chunked Body + // Event Stream +} + +pub struct HttpSigningConfig { + pub algorithm: SigningAlgorithm, + pub signature_type: HttpSignatureType, + pub service_config: ServiceConfig, + pub request_config: RequestConfig, + + pub double_uri_encode: bool, + pub normalize_uri_path: bool, + pub omit_session_token: bool, +} + +pub struct RequestConfig { + // the request config must enable recomputing the timestamp for retries, etc. + pub request_ts: fn() -> SystemTime, +} + +pub struct ServiceConfig { + pub service: String, + pub region: String, +} + +type SigningError = Box; + +use std::fmt::{Display, Formatter}; +use std::pin::Pin; +use std::task; +use std::task::Poll; + +#[derive(Clone)] +pub struct HttpSigner {} + +impl HttpSigner { + /// Sign an HTTP request + /// + /// You may need to modify the body of your HTTP request to be signable. + /// + /// NOTE: This design may change, a modified design that returns a SigningResult may be + /// used instead, this design allows for current compatibility with `aws-sigv4` + pub fn sign( + &self, + signing_config: &HttpSigningConfig, + credentials: &Credentials, + request: &mut http::Request, + payload: impl AsRef<[u8]>, + ) -> Result<(), SigningError> { + if signing_config.algorithm != SigningAlgorithm::SigV4 + || signing_config.double_uri_encode + || !signing_config.normalize_uri_path + || signing_config.omit_session_token + || signing_config.signature_type != HttpSignatureType::HttpRequestHeaders + { + unimplemented!() + } + // TODO: update the aws_sigv4 API to avoid needing the clone the credentials + let sigv4_creds = aws_sigv4::Credentials { + access_key: credentials.access_key_id.clone(), + secret_key: credentials.secret_access_key.clone(), + security_token: credentials.session_token.clone(), + }; + let date = (signing_config.request_config.request_ts)(); + for (key, value) in aws_sigv4::sign_core( + request, + payload, + &sigv4_creds, + &signing_config.service_config.region, + &signing_config.service_config.service, + date, + ) { + request + .headers_mut() + .append(key.header_name(), value.parse()?); + } + + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::{ + Credentials, CredentialsProviderError, HttpSignatureType, HttpSigner, HttpSigningConfig, + ProvideCredentials, RequestConfig, ServiceConfig, SigningAlgorithm, + }; + use std::error::Error; + use std::time::SystemTime; + + struct DynamoConfig { + signer: HttpSigner, + credentials_provider: Box, + service: String, + region: String, + time_source: fn() -> SystemTime, + } + + impl DynamoConfig { + pub fn from_env() -> Self { + let stub_creds = Credentials::from_static("asdf", "asef", None); + DynamoConfig { + signer: HttpSigner {}, + credentials_provider: Box::new(stub_creds), + service: "dynamodb".to_string(), + region: "us-east-1".to_string(), + time_source: || SystemTime::now(), + } + } + } + + struct ListTablesOperationInput { + field: u32, + } + + struct ListTablesOperation { + input: ListTablesOperationInput, + } + + impl ListTablesOperation { + pub fn raw_request( + &self, + _config: &DynamoConfig, + ) -> Result>, Box> { + let base = http::Request::new(vec![self.input.field as u8]); + Ok(base) + } + + pub async fn build_request(&self, config: &DynamoConfig) -> http::Request> { + let mut raw_request = self.raw_request(&config).unwrap(); + Self::finalize(&config, &mut raw_request).await; + raw_request + } + pub async fn finalize(config: &DynamoConfig, mut request: &mut http::Request>) { + let service_config = ServiceConfig { + service: config.service.clone(), + region: config.region.clone(), + }; + let signing_config = ListTablesOperation::signing_config( + RequestConfig { + request_ts: config.time_source, + }, + service_config, + ); + let credentials = config.credentials_provider.credentials().unwrap(); + config + .signer + .sign(&signing_config, &credentials, &mut request, &[1, 2, 3]) + .expect("signing failed"); + // Ok(base) + } + + fn signing_config( + request_config: RequestConfig, + service_config: ServiceConfig, + ) -> HttpSigningConfig { + // Different operations can use different signing configurations + HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config, + request_config, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + } + } + } + + impl ListTablesOperationInput { + fn build( + self, + _config: &DynamoConfig, + ) -> Result { + Ok(ListTablesOperation { input: self }) + } + } + + #[tokio::test] + async fn sign_operation() { + let inp = ListTablesOperationInput { field: 123 }; + let dynamo = DynamoConfig::from_env(); + // Various problems, eg. credentials provider error + let operation = inp.build(&dynamo).expect("failed to get creds"); + // Eg. signing error, expired credentials, etc. + let base_request = operation.build_request(&dynamo).await; + assert_eq!( + base_request + .headers() + .keys() + .map(|k| k.as_str()) + .collect::>(), + vec!["authorization", "x-amz-date"] + ); + } +} diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs new file mode 100644 index 0000000000..e40416106f --- /dev/null +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -0,0 +1,106 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use crate::middleware::OperationMiddleware; +use crate::Operation; +use core::convert::AsRef; +use http::uri::Uri; +use std::error::Error; +use std::str::FromStr; + +pub struct StaticEndpoint(http::Uri); + +impl StaticEndpoint { + pub fn uri(&self) -> &Uri { + &self.0 + } + pub fn from_service_region(svc: impl AsRef, region: impl AsRef) -> Self { + StaticEndpoint( + Uri::from_str(&format!( + "https://{}.{}.amazonaws.com", + svc.as_ref(), + region.as_ref() + )) + .unwrap(), + ) + } + + pub fn from_uri(uri: Uri) -> Self { + StaticEndpoint(uri) + } + + pub fn apply(&self, base_uri: &Uri) -> Uri { + let parts = self.0.clone().into_parts(); + + Uri::builder() + .authority(parts.authority.expect("base uri must have an authority")) + .scheme(parts.scheme.expect("base uri must have scheme")) + .path_and_query(base_uri.path_and_query().unwrap().clone()) + .build() + .expect("valid uri") + } +} + +pub trait ProvideEndpoint { + fn set_endpoint(&self, request_uri: &mut Uri); +} + +impl ProvideEndpoint for StaticEndpoint { + fn set_endpoint(&self, request_uri: &mut Uri) { + let new_uri = self.apply(request_uri); + *request_uri = new_uri; + } +} + +impl OperationMiddleware for T +where + T: ProvideEndpoint, +{ + fn apply(&self, request: &mut Operation) -> Result<(), Box> { + self.set_endpoint(&mut request.base.uri_mut()); + Ok(()) + } +} + +// TODO: this should probably move to a collection of middlewares +#[derive(Clone, Copy)] +/// Set the endpoint for a request based on the endpoint config +pub struct EndpointMiddleware; +impl OperationMiddleware for EndpointMiddleware { + fn apply(&self, request: &mut Operation) -> Result<(), Box> { + let endpoint_config = &request.endpoint_config; + endpoint_config.set_endpoint(&mut request.base.uri_mut()); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::endpoint::StaticEndpoint; + use http::Uri; + use std::str::FromStr; + + #[test] + fn endpoint_from_svc() { + let endpoint = StaticEndpoint::from_service_region("dynamodb", "us-west-2"); + assert_eq!( + endpoint.uri().to_string(), + "https://dynamodb.us-west-2.amazonaws.com/" + ); + } + + #[test] + fn properly_update_uri() { + let uri = Uri::builder() + .path_and_query("/get?k=123&v=456") + .build() + .unwrap(); + let endpoint = StaticEndpoint::from_uri(Uri::from_str("http://localhost:8080/").unwrap()); + assert_eq!( + endpoint.apply(&uri).to_string(), + "http://localhost:8080/get?k=123&v=456" + ); + } +} diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs new file mode 100644 index 0000000000..469c0c6bcc --- /dev/null +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -0,0 +1,262 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use crate::{Operation, SdkBody}; +use std::error::Error; +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; +use tower::{Layer, Service}; + +pub trait OperationMiddleware { + fn apply(&self, request: &mut Operation) -> Result<(), Box>; +} + +pub struct OperationRequestMiddlewareService { + inner: S, + middleware: M, +} + +pub struct OperationRequestMiddlewareLayer { + layer: M, +} + +impl OperationRequestMiddlewareLayer { + pub fn for_middleware(layer: M) -> Self { + OperationRequestMiddlewareLayer { layer } + } +} + +impl Layer for OperationRequestMiddlewareLayer +where + M: Clone, +{ + type Service = OperationRequestMiddlewareService; + + fn layer(&self, inner: S) -> Self::Service { + OperationRequestMiddlewareService { + inner, + middleware: self.layer.clone(), + } + } +} + +pub trait RequestConstructionErr { + fn request_error(err: Box) -> Self; +} + +#[pin_project(project = EnumProj)] +pub enum OperationMiddlewareFuture { + Inner(#[pin] F), + Ready(Option), +} + +impl Future for OperationMiddlewareFuture +where + F: Future>, +{ + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.project() { + EnumProj::Ready(e) => Poll::Ready(Err(e.take().unwrap())), + EnumProj::Inner(f) => f.poll(cx), + } + } +} + +impl Service> for OperationRequestMiddlewareService +where + S: Service>, + M: OperationMiddleware, + S::Error: RequestConstructionErr, +{ + type Response = S::Response; + type Error = S::Error; + type Future = OperationMiddlewareFuture; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, mut req: Operation) -> Self::Future { + if let Err(e) = self + .middleware + .apply(&mut req) + .map_err(|e| S::Error::request_error(e)) + { + return OperationMiddlewareFuture::Ready(Some(e)); + } + OperationMiddlewareFuture::Inner(self.inner.call(req)) + } +} + +/// Connects Operation driven middleware to an HTTP implementation. +/// +/// It will also wrap the error type in OperationError to enable operation middleware +/// reporting specific errors +pub struct DispatchMiddleware { + inner: S, +} + +pub struct DispatchLayer; + +impl Layer for DispatchLayer +where + S: Service>, +{ + type Service = DispatchMiddleware; + + fn layer(&self, inner: S) -> Self::Service { + DispatchMiddleware { inner } + } +} + +#[derive(Debug)] +pub enum OperationError { + DispatchError(E), + ConstructionError(Box), +} + +impl RequestConstructionErr for OperationError { + fn request_error(err: Box) -> Self { + OperationError::ConstructionError(err) + } +} + +use pin_project::pin_project; + +#[pin_project] +pub struct OperationFuture { + #[pin] + f: F, +} + +impl Future for OperationFuture +where + F: Future>, +{ + type Output = Result>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = self.project(); + this.f + .poll(cx) + .map_err(|e| OperationError::DispatchError(e)) + } +} + +impl Service> for DispatchMiddleware +where + S: Service>, +{ + type Response = S::Response; + type Error = OperationError; + type Future = OperationFuture; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner + .poll_ready(cx) + .map_err(|e| OperationError::DispatchError(e)) + } + + fn call(&mut self, req: Operation) -> Self::Future { + OperationFuture { + f: self.inner.call(req.base), + } + } +} + +#[cfg(test)] +mod test { + use crate::endpoint::StaticEndpoint; + use crate::middleware::{DispatchLayer, OperationMiddleware, OperationRequestMiddlewareLayer}; + use crate::{HttpRequestResponse, Operation, SdkBody}; + use auth::{ + Credentials, HttpSignatureType, HttpSigningConfig, RequestConfig, ServiceConfig, + SigningAlgorithm, SigningConfig, + }; + use http::header::HeaderName; + use http::{HeaderValue, Request, Response}; + use hyper::body::Bytes; + use std::convert::TryInto; + use std::error::Error; + use std::str::FromStr; + use std::time::{Instant, SystemTime}; + use tower::service_fn; + use tower::{Layer, Service}; + + struct TestOperationParser; + impl HttpRequestResponse for TestOperationParser { + type O = String; + + fn parse_unloaded(&self, response: &mut Response) -> Option { + Some("Hello!".to_string()) + } + + fn parse_loaded(&self, response: &Response) -> Self::O { + "Hello!".to_string() + } + } + + #[tokio::test] + async fn middleware_test() { + #[derive(Clone)] + struct AddHeader(String, String); + impl OperationMiddleware for AddHeader { + fn apply(&self, request: &mut Operation) -> Result<(), Box> { + request.base.headers_mut().append( + HeaderName::from_str(&self.0).unwrap(), + HeaderValue::from_str(&self.0).unwrap(), + ); + Ok(()) + } + } + + let add_header = OperationRequestMiddlewareLayer::for_middleware(AddHeader( + "X-Key".to_string(), + "X-Value".to_string(), + )); + let http_service = service_fn(|request: Request| async move { + if request.uri().to_string().as_str() == "123" { + Err("invalid url") + } else { + Ok(http::Response::new( + request + .headers() + .iter() + .map(|(k, v)| format!("{}:{:?}", k, v)) + .collect::(), + )) + } + }); + let mut service = add_header.layer(DispatchLayer.layer(http_service)); + let operation = Operation { + base: Request::builder() + .uri("/some_url") + .body(SdkBody::from("Hello")) + .unwrap(), + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + service: "svc".to_string(), + region: "region".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: false, + omit_session_token: false, + }), + credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), + endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), + response_handler: Box::new(TestOperationParser), + }; + let response = service.call(operation).await; + assert_eq!(response.unwrap().body(), "x-key:\"X-Key\""); + } +} diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs new file mode 100644 index 0000000000..9d68a93064 --- /dev/null +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -0,0 +1,42 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +use crate::middleware::OperationMiddleware; +use crate::Operation; +use crate::SdkBody; +use auth::{HttpSigner, SigningConfig}; +use std::error::Error; + +#[derive(Clone)] +pub struct SigningMiddleware { + signer: HttpSigner, +} + +impl SigningMiddleware { + pub fn new() -> Self { + SigningMiddleware { + signer: HttpSigner {}, + } + } +} + +impl OperationMiddleware for SigningMiddleware { + fn apply(&self, request: &mut Operation) -> Result<(), Box> { + let signing_config = &request.signing_config; + let creds = request.credentials_provider.credentials()?; + let body = match request.base.body() { + SdkBody::Once(Some(bytes)) => bytes.clone(), + SdkBody::Once(None) => bytes::Bytes::new(), + // in the future, chan variants which will cause an error + }; + match signing_config { + SigningConfig::Http(config) => { + if let Err(e) = self.signer.sign(config, &creds, &mut request.base, body) { + return Err(e); + } + } + }; + Ok(()) + } +} diff --git a/aws/rust-runtime/test.sh b/aws/rust-runtime/test.sh new file mode 100755 index 0000000000..1f5cd64f85 --- /dev/null +++ b/aws/rust-runtime/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0. +# + +set -e +for crate in "$(dirname "$0")"/*/ +do + if [ -d "$crate" ] && [ -f "$crate/Cargo.toml" ]; then + echo "Testing $crate" + (cd "$crate" && cargo fmt) + (cd "$crate" && cargo fmt -- --check) + (cd "$crate" && cargo clippy -- -D warnings) + (cd "$crate" && cargo test) + fi +done diff --git a/aws/sdk-codegen/build.gradle.kts b/aws/sdk-codegen/build.gradle.kts new file mode 100644 index 0000000000..7c7673f1a6 --- /dev/null +++ b/aws/sdk-codegen/build.gradle.kts @@ -0,0 +1,92 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +plugins { + kotlin("jvm") + jacoco + maven + `maven-publish` +} + +description = "AWS Specific Customizations for Smithy code generation" +extra["displayName"] = "Smithy :: Rust :: AWS Codegen" +extra["moduleName"] = "software.amazon.smithy.rustsdk" + +group = "software.amazon.software.amazon.smithy.rust.codegen.smithy" +version = "0.1.0" + +val smithyVersion: String by project + +dependencies { + implementation(project(":codegen")) + implementation("software.amazon.smithy:smithy-aws-protocol-tests:$smithyVersion") + implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") + implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion") +} + +tasks.compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} + +tasks.compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} + +// Reusable license copySpec +val licenseSpec = copySpec { + from("${project.rootDir}/LICENSE") + from("${project.rootDir}/NOTICE") +} + +// Configure jars to include license related info +tasks.jar { + metaInf.with(licenseSpec) + inputs.property("moduleName", project.name) + manifest { + attributes["Automatic-Module-Name"] = project.name + } +} + +val sourcesJar by tasks.creating(Jar::class) { + group = "publishing" + description = "Assembles Kotlin sources jar" + classifier = "sources" + from(sourceSets.getByName("main").allSource) +} + +tasks.test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + showStandardStreams = true + } +} + + +// Configure jacoco (code coverage) to generate an HTML report +tasks.jacocoTestReport { + reports { + xml.isEnabled = false + csv.isEnabled = false + html.destination = file("$buildDir/reports/jacoco") + } +} + +// Always run the jacoco test report after testing. +tasks["test"].finalizedBy(tasks["jacocoTestReport"]) + + +publishing { + publications { + create("default") { + from(components["java"]) + artifact(sourcesJar) + } + } + repositories { + maven { + url = uri("$buildDir/repository") + } + } +} 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 new file mode 100644 index 0000000000..e0ca6bf267 --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt @@ -0,0 +1,21 @@ +/* + * 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.rust.codegen.smithy.RustCodegenDecorator +import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig +import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization + +class AwsCodegenDecorator : RustCodegenDecorator { + override val name: String = "AwsSdkCodgenDecorator" + override val order: Byte = -1 + override fun configCustomizations( + protocolConfig: ProtocolConfig, + baseCustomizations: List + ): List { + return listOf(CredentialProviderConfig()) + baseCustomizations + } +} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt new file mode 100644 index 0000000000..87aac4975d --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt @@ -0,0 +1,48 @@ +/* + * 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.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.Local +import software.amazon.smithy.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig + +/** + * Just a Stub + * + * Augment the config object with the AWS-specific fields like service and region + */ +class CredentialProviderConfig : ConfigCustomization() { + override fun section(section: ServiceConfig) = writable { + when (section) { + is ServiceConfig.ConfigStruct -> rust("pub credentials_provider: Box,", CredentialsProvider) + is ServiceConfig.ConfigImpl -> emptySection + is ServiceConfig.BuilderStruct -> + rust("credentials_provider: Option>", CredentialsProvider) + ServiceConfig.BuilderImpl -> + rust( + """ + pub fn credentials_provider(mut self, credentials_provider: impl #T + 'static) -> Self { + self.credentials_provider = Some(Box::new(credentials_provider)); + self + } + """, + CredentialsProvider + ) + ServiceConfig.BuilderBuild -> rust( + "credentials_provider: self.credentials_provider.unwrap_or_else(|| Box::new(#T())),", + DefaultProvider + ) + } + } +} + +val Auth = CargoDependency("auth", Local("../")) +val CredentialsProvider = RuntimeType("ProvideCredentials", Auth, "auth") +val DefaultProvider = RuntimeType("default_provider", Auth, "auth") diff --git a/aws/sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator b/aws/sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator new file mode 100644 index 0000000000..1ceb403cac --- /dev/null +++ b/aws/sdk-codegen/src/main/resources/META-INF/services/software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator @@ -0,0 +1 @@ +software.amazon.smithy.rustsdk.AwsCodegenDecorator diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index 3f7fadcf46..c24562648a 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -21,7 +21,8 @@ val smithyVersion: String by project val sdkOutputDir = buildDir.resolve("aws-sdk") val awsServices = discoverServices() // TODO: smithy-http should be removed -val runtimeModules = listOf("smithy-types", "smithy-http") +val runtimeModules = listOf("smithy-types", "smithy-http", "io-v0") +val awsModules = listOf("auth", "operation", "aws-hyper") buildscript { val smithyVersion: String by project @@ -109,8 +110,20 @@ tasks.register("relocateRuntime") { include("$it/**") } exclude("**/target") + exclude("**/Cargo.lock") } into(sdkOutputDir) + +} + +tasks.register("relocateAwsRuntime") { + from("$rootDir/aws/rust-runtime") + awsModules.forEach { + include("$it/**") + } + exclude("**/target") + exclude("**/Cargo.lock") + into(sdkOutputDir) } fun generateCargoWorkspace(services: List): String { @@ -130,7 +143,7 @@ task("generateCargoWorkspace") { } task("finalizeSdk") { - finalizedBy("relocateServices", "relocateRuntime", "generateCargoWorkspace") + finalizedBy("relocateServices", "relocateRuntime", "relocateAwsRuntime", "generateCargoWorkspace") } tasks["smithyBuildJar"].dependsOn("generateSmithyBuild") @@ -170,6 +183,14 @@ tasks.register("cargoClippy") { dependsOn("assemble") } +tasks.register("dynamoIt") { + workingDir(projectDir.resolve("dynamo-it")) + // disallow warnings + commandLine("cargo", "run") + dependsOn("assemble") + +} + tasks["test"].finalizedBy("cargoCheck", "cargoClippy", "cargoTest", "cargoDocs") tasks["clean"].doFirst { diff --git a/codegen-test/dynamo-it/.gitignore b/aws/sdk/dynamo-it/.gitignore similarity index 100% rename from codegen-test/dynamo-it/.gitignore rename to aws/sdk/dynamo-it/.gitignore diff --git a/codegen-test/dynamo-it/Cargo.lock b/aws/sdk/dynamo-it/Cargo.lock similarity index 67% rename from codegen-test/dynamo-it/Cargo.lock rename to aws/sdk/dynamo-it/Cargo.lock index 925946178a..17182c046b 100644 --- a/codegen-test/dynamo-it/Cargo.lock +++ b/aws/sdk/dynamo-it/Cargo.lock @@ -1,29 +1,67 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "auth" +version = "0.1.0" +dependencies = [ + "aws-sigv4 0.0.1 (git+https://github.com/rcoh/sigv4)", + "http", +] + [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "aws-hyper" +version = "0.1.0" +dependencies = [ + "auth", + "bytes 1.0.0", + "http", + "http-body 0.4.0", + "hyper 0.14.2", + "hyper-tls", + "operation", + "pin-utils", + "tower 0.4.2", +] + [[package]] name = "aws-sigv4" version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85293e31cbf209322718ff220c48470f5dd31f39f652220bba6f3ceb2579cc81" dependencies = [ - "bytes", + "bytes 0.5.6", "chrono", "eliza_error", "hex", "http", - "http-body", + "http-body 0.3.1", "httparse", - "hyper", + "hyper 0.13.9", + "ring", + "serde", + "serde_urlencoded 0.5.5", + "tower 0.3.1", +] + +[[package]] +name = "aws-sigv4" +version = "0.0.1" +source = "git+https://github.com/rcoh/sigv4#ef394a689c695f057ce9870b38bf4b470efcfc36" +dependencies = [ + "bytes 1.0.0", + "chrono", + "hex", + "http", + "http-body 0.4.0", "ring", "serde", - "serde_urlencoded", - "tower", + "serde_urlencoded 0.7.0", ] [[package]] @@ -44,6 +82,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +[[package]] +name = "bytes" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f8e949d755f9d79112b5bb46938e0ef9d3804a0b16dfab13aafcaa5f0fa72" + [[package]] name = "cc" version = "1.0.66" @@ -75,6 +119,22 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + [[package]] name = "dtoa" version = "0.4.6" @@ -82,26 +142,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" [[package]] -name = "dynamo" -version = "0.0.1" +name = "dynamo-it" +version = "0.1.0" dependencies = [ + "auth", + "aws-hyper", + "bytes 1.0.0", + "dynamodb", "http", - "rand", - "serde", - "serde_json", - "smithy-http", + "io-v0", + "operation", + "rand 0.7.3", "smithy-types", + "tokio 1.0.1", ] [[package]] -name = "dynamo-it" -version = "0.1.0" +name = "dynamodb" +version = "0.0.1" dependencies = [ - "dynamo", - "io-v0", - "rand", + "auth", + "http", + "rand 0.7.3", + "serde", + "serde_json", + "smithy-http", "smithy-types", - "tokio", ] [[package]] @@ -116,6 +182,31 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +dependencies = [ + "matches", + "percent-encoding 2.1.0", +] + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -167,7 +258,7 @@ checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2" dependencies = [ "futures-core", "futures-task", - "pin-project 1.0.2", + "pin-project 1.0.4", "pin-utils", ] @@ -182,13 +273,24 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getrandom" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", +] + [[package]] name = "h2" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "futures-sink", @@ -196,8 +298,28 @@ dependencies = [ "http", "indexmap", "slab", - "tokio", - "tokio-util", + "tokio 0.2.24", + "tokio-util 0.3.1", + "tracing", + "tracing-futures", +] + +[[package]] +name = "h2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" +dependencies = [ + "bytes 1.0.0", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio 1.0.1", + "tokio-util 0.6.1", "tracing", "tracing-futures", ] @@ -225,11 +347,11 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "http" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ - "bytes", + "bytes 1.0.0", "fnv", "itoa", ] @@ -240,7 +362,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ - "bytes", + "bytes 0.5.6", + "http", +] + +[[package]] +name = "http-body" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" +dependencies = [ + "bytes 1.0.0", "http", ] @@ -262,24 +394,61 @@ version = "0.13.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ad767baac13b44d4529fcf58ba2cd0995e36e7b435bc5b039de6f47e880dbf" dependencies = [ - "bytes", + "bytes 0.5.6", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.2.7", + "http", + "http-body 0.3.1", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.4", + "socket2", + "tokio 0.2.24", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" +dependencies = [ + "bytes 1.0.0", "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.0", "http", - "http-body", + "http-body 0.4.0", "httparse", "httpdate", "itoa", - "pin-project 1.0.2", + "pin-project 1.0.4", "socket2", - "tokio", + "tokio 1.0.1", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes 1.0.0", + "hyper 0.14.2", + "native-tls", + "tokio 1.0.1", + "tokio-native-tls", +] + [[package]] name = "idna" version = "0.1.5" @@ -301,16 +470,25 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "io-v0" version = "0.1.0" dependencies = [ - "aws-sigv4", + "aws-sigv4 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "http", - "http-body", - "hyper", + "http-body 0.3.1", + "hyper 0.13.9", "pin-utils", - "tokio", + "tokio 0.2.24", ] [[package]] @@ -359,6 +537,15 @@ version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.11" @@ -399,6 +586,19 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +dependencies = [ + "libc", + "log", + "miow 0.3.6", + "ntapi", + "winapi 0.3.9", +] + [[package]] name = "mio-named-pipes" version = "0.1.7" @@ -406,7 +606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log", - "mio", + "mio 0.6.23", "miow 0.3.6", "winapi 0.3.9", ] @@ -419,7 +619,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio", + "mio 0.6.23", ] [[package]] @@ -444,6 +644,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "native-tls" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "net2" version = "0.2.37" @@ -455,6 +673,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -490,12 +717,88 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +[[package]] +name = "openssl" +version = "0.10.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "operation" +version = "0.1.0" +dependencies = [ + "auth", + "bytes 1.0.0", + "http", + "http-body 0.4.0", + "pin-project 1.0.4", + "tower 0.4.2", +] + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi 0.3.9", +] + [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "pin-project" version = "0.4.27" @@ -507,11 +810,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" +checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" dependencies = [ - "pin-project-internal 1.0.2", + "pin-project-internal 1.0.4", ] [[package]] @@ -527,9 +830,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" +checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" dependencies = [ "proc-macro2", "quote", @@ -554,6 +857,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -584,11 +893,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24fcd450d3fa2b592732565aa4f17a27a61c65ece4726353e000939b0edee34" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.0", ] [[package]] @@ -598,7 +919,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.1", ] [[package]] @@ -607,7 +938,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom 0.2.1", ] [[package]] @@ -616,7 +956,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.1", ] [[package]] @@ -625,6 +974,24 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ring" version = "0.16.19" @@ -646,6 +1013,45 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi 0.3.9", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.118" @@ -689,6 +1095,18 @@ dependencies = [ "url", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "signal-hook-registry" version = "1.2.2" @@ -704,6 +1122,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + [[package]] name = "smithy-http" version = "0.0.1" @@ -726,7 +1150,7 @@ checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "winapi 0.3.9", ] @@ -747,6 +1171,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.1", + "redox_syscall 0.2.4", + "remove_dir_all", + "winapi 0.3.9", +] + [[package]] name = "time" version = "0.1.44" @@ -779,21 +1217,41 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "iovec", "lazy_static", "libc", "memchr", - "mio", + "mio 0.6.23", "mio-named-pipes", "mio-uds", "num_cpus", "pin-project-lite 0.1.11", "signal-hook-registry", "slab", - "tokio-macros", + "tokio-macros 0.2.6", + "winapi 0.3.9", +] + +[[package]] +name = "tokio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d258221f566b6c803c7b4714abadc080172b272090cdc5e244a6d4dd13c3a6bd" +dependencies = [ + "autocfg", + "bytes 1.0.0", + "libc", + "memchr", + "mio 0.7.7", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite 0.2.0", + "signal-hook-registry", + "tokio-macros 1.0.0", "winapi 0.3.9", ] @@ -808,18 +1266,65 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio 1.0.1", +] + +[[package]] +name = "tokio-stream" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4cdeb73537e63f98adcd73138af75e3f368ccaecffaa29d7eb61b9f5a440457" +dependencies = [ + "futures-core", + "pin-project-lite 0.2.0", + "tokio 1.0.1", +] + [[package]] name = "tokio-util" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", "pin-project-lite 0.1.11", - "tokio", + "tokio 0.2.24", +] + +[[package]] +name = "tokio-util" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ae4751faa60b9f96dd8344d74592e5a17c0c9a220413dbc6942d14139bbfcc" +dependencies = [ + "bytes 1.0.0", + "futures-core", + "futures-sink", + "log", + "pin-project-lite 0.2.0", + "tokio 1.0.1", + "tokio-stream", ] [[package]] @@ -840,6 +1345,20 @@ dependencies = [ "tower-util", ] +[[package]] +name = "tower" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed5c471f00236abe8c633860d8234646cb4993eaad7720844f79bb1b94e949b" +dependencies = [ + "futures-core", + "futures-util", + "pin-project 1.0.4", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-buffer" version = "0.3.0" @@ -848,7 +1367,7 @@ checksum = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a" dependencies = [ "futures-core", "pin-project 0.4.27", - "tokio", + "tokio 0.2.24", "tower-layer", "tower-service", "tracing", @@ -867,9 +1386,9 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35d656f2638b288b33495d1053ea74c40dc05ec0b92084dd71ca5566c4ed1dc" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" [[package]] name = "tower-limit" @@ -879,7 +1398,7 @@ checksum = "92c3040c5dbed68abffaa0d4517ac1a454cd741044f33ab0eefab6b8d1361404" dependencies = [ "futures-core", "pin-project 0.4.27", - "tokio", + "tokio 0.2.24", "tower-layer", "tower-load", "tower-service", @@ -894,7 +1413,7 @@ dependencies = [ "futures-core", "log", "pin-project 0.4.27", - "tokio", + "tokio 0.2.24", "tower-discover", "tower-service", ] @@ -919,7 +1438,7 @@ checksum = "e6727956aaa2f8957d4d9232b308fe8e4e65d99db30f42b225646e86c9b6a952" dependencies = [ "futures-core", "pin-project 0.4.27", - "tokio", + "tokio 0.2.24", "tower-layer", "tower-service", ] @@ -937,7 +1456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "127b8924b357be938823eaaec0608c482d40add25609481027b96198b2e4b31e" dependencies = [ "pin-project 0.4.27", - "tokio", + "tokio 0.2.24", "tower-layer", "tower-service", ] @@ -1041,9 +1560,15 @@ checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ "idna", "matches", - "percent-encoding", + "percent-encoding 1.0.1", ] +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + [[package]] name = "want" version = "0.3.0" diff --git a/aws/sdk/dynamo-it/Cargo.toml b/aws/sdk/dynamo-it/Cargo.toml new file mode 100644 index 0000000000..5885ccbe83 --- /dev/null +++ b/aws/sdk/dynamo-it/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "dynamo-it" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +smithy-types = { path = "../build/aws-sdk/smithy-types" } +dynamodb = { version = "0.0.1", path = "../build/aws-sdk/dynamodb"} +io-v0 = { path = "../build/aws-sdk/io-v0" } +aws-hyper = { path = "../build/aws-sdk/aws-hyper"} +tokio = { version = "1", features = ["full"] } +rand = "0.7.3" +bytes = "1" + + +# these are just for the stub implementation +operation = { path = "../build/aws-sdk/operation"} +auth = { path = "../build/aws-sdk/auth" } +http = "0.2.3" diff --git a/codegen-test/dynamo-it/docker-compose.yml b/aws/sdk/dynamo-it/docker-compose.yml similarity index 100% rename from codegen-test/dynamo-it/docker-compose.yml rename to aws/sdk/dynamo-it/docker-compose.yml diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs new file mode 100644 index 0000000000..794fcd551b --- /dev/null +++ b/aws/sdk/dynamo-it/src/main.rs @@ -0,0 +1,153 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use std::error::Error; + +use dynamodb::model::{ + AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, +}; +use dynamodb::operation::CreateTable; +use dynamodb::output::{ListTablesOutput, DeleteTableOutput}; +use operation::{HttpRequestResponse, SdkBody, Operation}; +use dynamodb::error::DeleteTableError; + +struct DeleteTable(dynamodb::operation::DeleteTable); + +use bytes::Bytes; +use auth::{SigningConfig, HttpSigningConfig, SigningAlgorithm, HttpSignatureType, ServiceConfig, RequestConfig}; +use std::time::SystemTime; +use operation::endpoint::StaticEndpoint; +use http::{Response, Uri}; + +impl HttpRequestResponse for DeleteTable { + type O = Result; + + fn parse_unloaded(&self, _: &mut Response) -> Option { + None + } + + fn parse_loaded(&self, response: &Response) -> Self::O { + self.0.parse_response(response) + } +} + +impl DeleteTable { + fn into_operation(self, config: dynamodb::Config) -> Operation { + Operation { + base: self.0.build_http_request().map(|body|SdkBody::from(body)), + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + // TODO: these get loaded from the config + service: "dynamodb".to_string(), + region: "us-east-1".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + }), + credentials_provider: config.credentials_provider, + endpoint_config: Box::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))), + response_handler: Some(Box::new(self)), + } + } +} + + +#[tokio::main] +async fn main() -> Result<(), Box> { + let table_name = "new_table"; + let client = aws_hyper::Client::default(); + let config = dynamodb::Config::builder().build(); + let clear_table = dynamodb::operation::DeleteTable::builder() + .table_name(table_name) + .build(&config); + let clear_table = DeleteTable(clear_table); + match client.call(clear_table.into_operation(config)).await { + Ok(response) => println!("OK! {:?}", response.parsed), + Err(_response) => println!("failure: {}", _response.error()) + } + + /* + match io_v0::dispatch!(client, clear_table).parsed() { + Ok(Ok(table_deleted)) => println!( + "{:?} was deleted", + table_deleted + .table_description + .as_ref() + .unwrap() + .table_name + .as_ref() + .unwrap() + ), + Ok(Err(table_del_error)) => println!("failed to delete table: {}", table_del_error), + Err(e) => println!("dispatch error: {:?}", e), + } + + let tables = io_v0::dispatch!( + client, + dynamodb::operation::ListTables::builder().build(&config) + ) + .parsed + .unwrap(); + assert_eq!( + tables.unwrap(), + ListTablesOutput::builder().table_names(vec![]).build() + ); + println!("no tables...creating table"); + + let create_table = CreateTable::builder() + .table_name(table_name) + .attribute_definitions(vec![AttributeDefinition::builder() + .attribute_name("ForumName") + .attribute_type(ScalarAttributeType::S) + .build()]) + .key_schema(vec![KeySchemaElement::builder() + .attribute_name("ForumName") + .key_type(KeyType::Hash) + .build()]) + .provisioned_throughput( + ProvisionedThroughput::builder() + .read_capacity_units(100) + .write_capacity_units(100) + .build(), + ) + .build(&config); + + let response = io_v0::dispatch!(client, create_table); + match response.parsed { + Some(Ok(output)) => { + assert_eq!( + output.table_description.unwrap().table_name.unwrap(), + table_name + ); + println!("{} was created", table_name); + } + _ => println!("{:?}", response.raw), + } + + let tables = io_v0::dispatch!( + client, + dynamodb::operation::ListTables::builder().build(&config) + ) + .parsed + .unwrap(); + println!( + "current tables: {:?}", + &tables.as_ref().unwrap().table_names + ); + assert_eq!( + tables.unwrap(), + ListTablesOutput::builder() + .table_names(vec![table_name.to_string()]) + .build() + );*/ + + Ok(()) +} diff --git a/codegen-test/dynamo-it/Cargo.toml b/codegen-test/dynamo-it/Cargo.toml deleted file mode 100644 index 0ea6fe2555..0000000000 --- a/codegen-test/dynamo-it/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "dynamo-it" -version = "0.1.0" -authors = ["Russell Cohen "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -smithy-types = { path = "../../rust-runtime/smithy-types" } -dynamo = { version = "0.0.1", path = "../build/smithyprojections/codegen-test/dynamo/rust-codegen/"} -io-v0 = { path = "../../rust-runtime/io-v0" } -tokio = { version = "0.2", features = ["full"] } -rand = "0.7.3" diff --git a/codegen-test/dynamo-it/src/main.rs b/codegen-test/dynamo-it/src/main.rs deleted file mode 100644 index 9c9c53a0ba..0000000000 --- a/codegen-test/dynamo-it/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -use std::error::Error; - -use dynamo::model::{ - AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, -}; -use dynamo::operation::CreateTable; -use dynamo::output::ListTablesOutput; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let table_name = "new_table"; - let client = io_v0::Client::local("dynamodb"); - let config = dynamo::Config::from_env(); - let clear_table = dynamo::operation::DeleteTable::builder() - .table_name(table_name) - .build(&config); - match io_v0::dispatch!(client, clear_table).parsed() { - Ok(Ok(table_deleted)) => println!( - "{:?} was deleted", - table_deleted - .table_description - .as_ref() - .unwrap() - .table_name - .as_ref() - .unwrap() - ), - Ok(Err(table_del_error)) => println!("failed to delete table: {}", table_del_error), - Err(e) => println!("dispatch error: {:?}", e), - } - - let tables = io_v0::dispatch!( - client, - dynamo::operation::ListTables::builder().build(&config) - ) - .parsed - .unwrap(); - assert_eq!( - tables.unwrap(), - ListTablesOutput::builder().table_names(vec![]).build() - ); - println!("no tables...creating table"); - - let create_table = CreateTable::builder() - .table_name(table_name) - .attribute_definitions(vec![AttributeDefinition::builder() - .attribute_name("ForumName") - .attribute_type(ScalarAttributeType::S) - .build()]) - .key_schema(vec![KeySchemaElement::builder() - .attribute_name("ForumName") - .key_type(KeyType::Hash) - .build()]) - .provisioned_throughput( - ProvisionedThroughput::builder() - .read_capacity_units(100) - .write_capacity_units(100) - .build(), - ) - .build(&config); - - let response = io_v0::dispatch!(client, create_table); - match response.parsed { - Some(Ok(output)) => { - assert_eq!( - output.table_description.unwrap().table_name.unwrap(), - table_name - ); - println!("{} was created", table_name); - } - _ => println!("{:?}", response.raw), - } - - let tables = io_v0::dispatch!( - client, - dynamo::operation::ListTables::builder().build(&config) - ) - .parsed - .unwrap(); - println!( - "current tables: {:?}", - &tables.as_ref().unwrap().table_names - ); - assert_eq!( - tables.unwrap(), - ListTablesOutput::builder() - .table_names(vec![table_name.to_string()]) - .build() - ); - - Ok(()) -} diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt index 46e4112546..8d4e7255dd 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt @@ -25,7 +25,6 @@ import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolGeneratorFa import software.amazon.smithy.rust.codegen.smithy.generators.ServiceGenerator import software.amazon.smithy.rust.codegen.smithy.generators.StructureGenerator import software.amazon.smithy.rust.codegen.smithy.generators.UnionGenerator -import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolLoader import software.amazon.smithy.rust.codegen.smithy.traits.SyntheticInputTrait @@ -34,7 +33,7 @@ import software.amazon.smithy.rust.codegen.util.CommandFailed import software.amazon.smithy.rust.codegen.util.runCommand import java.util.logging.Logger -class CodegenVisitor(context: PluginContext, codegenDecorator: RustCodegenDecorator) : ShapeVisitor.Default() { +class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustCodegenDecorator) : ShapeVisitor.Default() { private val logger = Logger.getLogger(javaClass.name) private val settings = RustSettings.from(context.model, context.settings) @@ -46,7 +45,6 @@ class CodegenVisitor(context: PluginContext, codegenDecorator: RustCodegenDecora private val protocolConfig: ProtocolConfig private val protocolGenerator: ProtocolGeneratorFactory private val httpGenerator: HttpProtocolGenerator - private val configCustomizations: List init { val symbolVisitorConfig = @@ -66,7 +64,6 @@ class CodegenVisitor(context: PluginContext, codegenDecorator: RustCodegenDecora RustWriter.Factory ) httpGenerator = protocolGenerator.buildProtocolGenerator(protocolConfig) - configCustomizations = codegenDecorator.configCustomizations(protocolConfig, listOf()) } private fun baselineTransform(model: Model) = RecursiveShapeBoxer.transform(model) @@ -120,6 +117,6 @@ class CodegenVisitor(context: PluginContext, codegenDecorator: RustCodegenDecora } override fun serviceShape(shape: ServiceShape) { - ServiceGenerator(writers, httpGenerator, protocolGenerator.support(), protocolConfig, configCustomizations).render() + ServiceGenerator(writers, httpGenerator, protocolGenerator.support(), protocolConfig, codegenDecorator).render() } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustCodegenDecorator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustCodegenDecorator.kt index be679d0037..cb67a8e6a1 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustCodegenDecorator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustCodegenDecorator.kt @@ -6,7 +6,9 @@ package software.amazon.smithy.rust.codegen.smithy import software.amazon.smithy.build.PluginContext +import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolMap @@ -24,17 +26,23 @@ interface RustCodegenDecorator { /** * The name of this [RustCodegenDecorator], used for logging and debug information */ - abstract val name: String + val name: String /** * Enable a deterministic ordering to be applied, with the lowest numbered integrations being applied first */ - abstract val order: Byte + val order: Byte fun configCustomizations( protocolConfig: ProtocolConfig, baseCustomizations: List ): List = baseCustomizations + fun operationCustomizations( + protocolConfig: ProtocolConfig, + operation: OperationShape, + baseCustomizations: List + ): List = baseCustomizations + fun protocols(serviceId: ShapeId, currentProtocols: ProtocolMap): ProtocolMap = currentProtocols fun symbolProvider(baseProvider: RustSymbolProvider): RustSymbolProvider = baseProvider @@ -66,6 +74,14 @@ class CombinedCodegenDecorator(decorators: List) : RustCod return orderedDecorators.foldRight(baseProvider) { decorator, provider -> decorator.symbolProvider(provider) } } + override fun operationCustomizations( + protocolConfig: ProtocolConfig, + operation: OperationShape, + baseCustomizations: List + ): List { + return orderedDecorators.foldRight(baseCustomizations) { decorator, customizations -> decorator.operationCustomizations(protocolConfig, operation, customizations) } + } + companion object { private val logger = Logger.getLogger("RustCodegenSPILoader") fun fromClasspath(context: PluginContext): RustCodegenDecorator { diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt index 1d9b371bc0..77ecd92370 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt @@ -16,6 +16,8 @@ import software.amazon.smithy.rust.codegen.rustlang.rustBlock import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.smithy.generators.config.NamedSectionGenerator +import software.amazon.smithy.rust.codegen.smithy.generators.config.Section import software.amazon.smithy.rust.codegen.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.util.inputShape import software.amazon.smithy.rust.codegen.util.outputShape @@ -38,6 +40,12 @@ interface ProtocolGeneratorFactory { fun support(): ProtocolSupport } +sealed class OperationSection(name: String) : Section(name) { + object ImplBlock : OperationSection("ImplBlock") +} + +typealias OperationCustomization = NamedSectionGenerator + /** * Abstract class providing scaffolding for HTTP based protocols that must build an HTTP request (headers / URL) and * a body. @@ -47,7 +55,12 @@ abstract class HttpProtocolGenerator( ) { private val symbolProvider = protocolConfig.symbolProvider private val model = protocolConfig.model - fun renderOperation(operationWriter: RustWriter, inputWriter: RustWriter, operationShape: OperationShape) { + fun renderOperation( + operationWriter: RustWriter, + inputWriter: RustWriter, + operationShape: OperationShape, + customizations: List + ) { val inputShape = operationShape.inputShape(model) val inputSymbol = symbolProvider.toSymbol(inputShape) val builderGenerator = OperationInputBuilderGenerator(model, symbolProvider, operationShape) @@ -100,6 +113,8 @@ abstract class HttpProtocolGenerator( rustBlock("pub fn new(input: #T) -> Self", inputSymbol) { write("Self { input }") } + + customizations.forEach { customization -> customization.section(OperationSection.ImplBlock)(this) } } } @@ -120,7 +135,11 @@ abstract class HttpProtocolGenerator( } } - protected fun fromResponseFun(implBlockWriter: RustWriter, operationShape: OperationShape, f: RustWriter.() -> Unit) { + protected fun fromResponseFun( + implBlockWriter: RustWriter, + operationShape: OperationShape, + f: RustWriter.() -> Unit + ) { implBlockWriter.rustBlock( "fn from_response(response: &#T>) -> Result<#T, #T>", RuntimeType.Http("response::Response"), @@ -145,5 +164,9 @@ abstract class HttpProtocolGenerator( * * Your implementation MUST call [httpBuilderFun] to create the public method. */ - abstract fun toHttpRequestImpl(implBlockWriter: RustWriter, operationShape: OperationShape, inputShape: StructureShape) + abstract fun toHttpRequestImpl( + implBlockWriter: RustWriter, + operationShape: OperationShape, + inputShape: StructureShape + ) } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/ServiceGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/ServiceGenerator.kt index 34c2452aea..163afcfc81 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/ServiceGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/ServiceGenerator.kt @@ -10,7 +10,7 @@ import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfigGenerator import software.amazon.smithy.rust.codegen.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.smithy.traits.SyntheticOutputTrait @@ -21,7 +21,7 @@ class ServiceGenerator( private val protocolGenerator: HttpProtocolGenerator, private val protocolSupport: ProtocolSupport, private val config: ProtocolConfig, - private val extraCustomizations: List, + private val decorator: RustCodegenDecorator, ) { private val index = TopDownIndex.of(config.model) @@ -30,7 +30,7 @@ class ServiceGenerator( operations.map { operation -> writers.useShapeWriter(operation) { operationWriter -> writers.useShapeWriter(operation.inputShape(config.model)) { inputWriter -> - protocolGenerator.renderOperation(operationWriter, inputWriter, operation) + protocolGenerator.renderOperation(operationWriter, inputWriter, operation, decorator.operationCustomizations(config, operation, listOf())) HttpProtocolTestGenerator(config, protocolSupport, operation, operationWriter).render() } } @@ -42,7 +42,7 @@ class ServiceGenerator( renderBodies(operations) writers.useFileWriter("src/config.rs", "crate::config") { writer -> - ServiceConfigGenerator.withBaseBehavior(config, extraCustomizations = extraCustomizations).render(writer) + ServiceConfigGenerator.withBaseBehavior(config, extraCustomizations = decorator.configCustomizations(config, listOf())).render(writer) } writers.useFileWriter("src/lib.rs", "crate::lib") { it.write("pub use config::Config;") diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/IdempotencyProviderConfig.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/IdempotencyProviderConfig.kt index 74a658bffb..2d11b587d6 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/IdempotencyProviderConfig.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/IdempotencyProviderConfig.kt @@ -14,29 +14,32 @@ import software.amazon.smithy.rust.codegen.smithy.RuntimeType * Add a `token_provider` field to Service config. See below for the resulting generated code. */ class IdempotencyProviderConfig : NamedSectionGenerator() { - override fun section(section: ServiceConfig): Writable { - return when (section) { - is ServiceConfig.ConfigStruct -> writable { - rust("pub (crate) token_provider: Box,", RuntimeType.IdempotencyToken) + override fun section(section: ServiceConfig): Writable = writable { + when (section) { + is ServiceConfig.ConfigStruct -> rust( + "pub (crate) token_provider: Box,", + RuntimeType.IdempotencyToken + ) + is ServiceConfig.ConfigImpl -> { } - ServiceConfig.ConfigImpl -> emptySection - ServiceConfig.BuilderStruct -> writable { - rust("token_provider: Option>", RuntimeType.IdempotencyToken) - } - ServiceConfig.BuilderImpl -> writable { - rust( - """ + is ServiceConfig.BuilderStruct -> rust( + "token_provider: Option>,", + RuntimeType.IdempotencyToken + ) + is ServiceConfig.BuilderImpl -> rust( + """ pub fn token_provider(mut self, token_provider: impl #T::ProvideIdempotencyToken + 'static) -> Self { self.token_provider = Some(Box::new(token_provider)); self } """, + RuntimeType.IdempotencyToken + ) + is ServiceConfig.BuilderBuild -> + rust( + "token_provider: self.token_provider.unwrap_or_else(|| Box::new(#T::default_provider())),", RuntimeType.IdempotencyToken ) - } - ServiceConfig.BuilderBuild -> writable { - rust("token_provider: self.token_provider.unwrap_or_else(|| Box::new(#T::default_provider())),", RuntimeType.IdempotencyToken) - } } } } From edbcba98c84d5417ff2f65f0f1c344dd6a83acd5 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 12 Jan 2021 18:23:21 -0500 Subject: [PATCH 03/50] Missing files --- aws/rust-runtime/.gitignore | 2 + aws/rust-runtime/auth/src/lib.rs | 22 --- aws/rust-runtime/aws-hyper/Cargo.toml | 21 +++ aws/rust-runtime/aws-hyper/src/lib.rs | 249 ++++++++++++++++++++++++++ aws/rust-runtime/operation/Cargo.toml | 18 ++ aws/rust-runtime/operation/src/lib.rs | 97 ++++++++++ 6 files changed, 387 insertions(+), 22 deletions(-) create mode 100644 aws/rust-runtime/.gitignore create mode 100644 aws/rust-runtime/aws-hyper/Cargo.toml create mode 100644 aws/rust-runtime/aws-hyper/src/lib.rs create mode 100644 aws/rust-runtime/operation/Cargo.toml create mode 100644 aws/rust-runtime/operation/src/lib.rs diff --git a/aws/rust-runtime/.gitignore b/aws/rust-runtime/.gitignore new file mode 100644 index 0000000000..1e7caa9ea8 --- /dev/null +++ b/aws/rust-runtime/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target/ diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 30a22d64db..2a5333f0c1 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -60,28 +60,6 @@ impl Display for CredentialsProviderError { impl Error for CredentialsProviderError {} -/// A `Future` that will resolve to Credentials or a credentials loading error -/// -/// This is returned by ProvideCredentials -#[must_use = "futures do nothing unless polled"] -pub struct CredentialsFuture { - inner: Pin> + Send>>, -} - -impl Future for CredentialsFuture { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { - Pin::new(&mut self.inner).poll(cx) - } -} - -impl CredentialsFuture { - pub fn ready(credentials: Credentials) -> Self { - let inner = Pin::new(Box::new(std::future::ready(Ok(credentials)))); - CredentialsFuture { inner } - } -} // TODO type CredentialsError = Box; diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml new file mode 100644 index 0000000000..67adc582d4 --- /dev/null +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "aws-hyper" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hyper = { version = "0.14.2", features = ["client", "http1", "http2"] } +tower = "0.4.2" +operation = { path = "../operation" } +hyper-tls = "0.5.0" +auth = { path = "../auth" } +http = "0.2.3" +bytes = "1" +http-body = "0.4.0" +pin-utils = "0.1.0" + +[dev-dependencies] +tokio = { version = "1", features = ["full"]} diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs new file mode 100644 index 0000000000..3b6756ad00 --- /dev/null +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -0,0 +1,249 @@ +use bytes::{Buf, Bytes}; +use operation::{HttpRequestResponse, Operation, SdkBody, middleware::OperationError}; +use std::error::Error; +use tower::util::ReadyOneshot; +use tower::{Layer, Service}; +use hyper::{Client as HyperClient}; + +type ResponseBody = hyper::Body; + +#[derive(Debug)] +pub struct SdkResponse { + pub raw: http::Response, + pub parsed: O, +} + +pub enum SdkError { + DispatchFailure(Box), + ResponseError { + raw: http::Response, + err: Box, + }, + ServiceError { + raw: http::Response, + err: E, + }, +} + +impl SdkError { + pub fn error(self) -> Box { + match self { + SdkError::DispatchFailure(e) => e, + SdkError::ResponseError { err, .. } => err, + SdkError::ServiceError { err, .. } => Box::new(err) + } + } +} + +pub struct Client { + inner: S, +} + +impl Client, SdkBody>> { + pub fn default() -> Self { + let https = HttpsConnector::new(); + let client = HyperClient::builder() + .build::<_, SdkBody>(https); + Client { + inner: client + } + } +} + +impl Client + where + S: Service, Response=http::Response> + Clone, + S::Error: std::error::Error + 'static, +{ + pub async fn call(&self, mut input: Operation) -> Result, SdkError> + where + // TODO: clean up the way that response handlers work—should they be disconnected from the operation, + // at least at this level of the API? + O: HttpRequestResponse>, + { + let ready_service = ReadyOneshot::new(self.inner.clone()) + .await + .map_err(|e| SdkError::DispatchFailure(e.into()))?; + + let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); + let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); + let mut ready_service = signer.layer(endpoint_resolver.layer(DispatchLayer.layer(ready_service))); + let handler = input.response_handler.take().unwrap(); + let mut response: http::Response = ready_service + .call(input) + .await + .map_err(|e| match e { + OperationError::DispatchError(e) => SdkError::DispatchFailure(Box::new(e)), + OperationError::ConstructionError(e) => SdkError::DispatchFailure(e) + })?; + + let parsed = handler.parse_unloaded(&mut response); + let mut response = match parsed { + Some(Ok(r)) => { + return Ok(SdkResponse { + raw: response, + parsed: r, + }); + } + Some(Err(e)) => { + return Err(SdkError::ServiceError { + raw: response, + err: e, + }); + } + None => response, + }; + + let body = match read_body(response.body_mut()).await { + Ok(body) => body, + Err(e) => { + return Err(SdkError::ResponseError { + raw: response, + err: Box::new(e), + }); + } + }; + + let response = response.map(|_| Bytes::from(body)); + let parsed = handler.parse_loaded(&response); + let raw = response.map(|bytes| hyper::Body::from(bytes)); + match parsed { + Ok(parsed) => Ok(SdkResponse { raw, parsed }), + Err(err) => Err(SdkError::ServiceError { raw, err }), + } + } +} + +use http_body; +use http_body::Body; +use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; +use operation::signing_middleware::SigningMiddleware; +use operation::endpoint::EndpointMiddleware; +use hyper_tls::HttpsConnector; +use hyper::client::HttpConnector; + +async fn read_body(body: B) -> Result, B::Error> { + let mut output = Vec::new(); + pin_utils::pin_mut!(body); + while let Some(buf) = body.data().await { + let mut buf = buf?; + while buf.has_remaining() { + output.extend_from_slice(buf.chunk()); + buf.advance(buf.chunk().len()) + } + } + Ok(output) +} + +#[cfg(test)] +mod test { + use operation::{Operation, HttpRequestResponse, SdkBody}; + use std::time::SystemTime; + use operation::endpoint::StaticEndpoint; + use http::{Response, Request}; + use bytes::Bytes; + use std::sync::{Arc, Mutex}; + use hyper::service::service_fn; + use crate::{read_body, Client}; + use auth::{SigningConfig, HttpSigningConfig, SigningAlgorithm, HttpSignatureType, ServiceConfig, RequestConfig, Credentials}; + use tower::Service; + use std::error::Error; + use pin_utils::core_reexport::fmt::Formatter; + + #[derive(Clone)] + struct TestOperationParser; + impl HttpRequestResponse for TestOperationParser { + type O = Result; + + fn parse_unloaded(&self, _response: &mut Response) -> Option { + Some(Ok("Hello!".to_string())) + } + + fn parse_loaded(&self, _response: &Response) -> Self::O { + Ok("Hello!".to_string()) + } + } + + #[tokio::test] + async fn e2e_service() { + + #[derive(Debug)] + struct TestError; + + impl std::fmt::Display for TestError { + fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { + unimplemented!() + } + } + impl Error for TestError {}; + + let operation = Operation { + base: Request::builder() + .uri("/some_url") + .body(SdkBody::from("Hello")) + .unwrap(), + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + service: "svc".to_string(), + region: "region".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + }), + credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), + endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), + response_handler: Some(Box::new(TestOperationParser)), + }; + + let test_request: Arc>>> = Arc::new(Mutex::new(None)); + let http_service = service_fn(|request: Request| async { + let mut request = request; + let body = read_body(request.body_mut()).await.unwrap(); + *(test_request.clone().lock().unwrap()) = Some(request.map(|_|Bytes::from(body))); + Result::, TestError>::Ok(Response::new(hyper::Body::from("hello!"))) + }); + //let x: () = http_service; + //http_service.call(http::Request::new(SdkBody::from("123"))); + let client = Client { inner: http_service }; + let response = client.call(operation).await; + let request = test_request.lock().unwrap().take().unwrap(); + assert_eq!(request.headers().keys().map(|it|it.as_str()).collect::>(), vec!["authorization", "x-amz-date"]); + assert!(response.is_ok()); + + } + + #[test] + fn real_service() { + let operation = Operation { + base: Request::builder() + .uri("/some_url") + .body(SdkBody::from("Hello")) + .unwrap(), + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + service: "svc".to_string(), + region: "region".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + }), + credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), + endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), + response_handler: Some(Box::new(TestOperationParser)), + }; + let client = Client::default(); + let _ = client.call(operation); + } +} diff --git a/aws/rust-runtime/operation/Cargo.toml b/aws/rust-runtime/operation/Cargo.toml new file mode 100644 index 0000000000..aee0828625 --- /dev/null +++ b/aws/rust-runtime/operation/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "operation" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +auth = { path = "../auth" } +http = "0.2.3" +bytes = "1" +tower = { version = "0.4.2", features = ["util"] } +http-body = "0.4.0" +pin-project = "1.0.4" + +[dev-dependencies] +tokio = { version = "1", features = ["full"] } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs new file mode 100644 index 0000000000..0c592a0b8c --- /dev/null +++ b/aws/rust-runtime/operation/src/lib.rs @@ -0,0 +1,97 @@ +use bytes::Bytes; + +use auth::{ProvideCredentials, SigningConfig}; + +pub mod endpoint; +pub mod middleware; +pub mod signing_middleware; + +use endpoint::ProvideEndpoint; +use http::{HeaderValue, HeaderMap}; +use std::error::Error; +use std::fmt::Debug; +use std::pin::Pin; +use std::task::{Context, Poll}; + +type BodyError = Box; + +pub enum SdkBody { + Once(Option), +} + +impl http_body::Body for SdkBody { + type Data = Bytes; + type Error = BodyError; + + fn poll_data( + mut self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll>> { + self.poll_inner() + } + + fn poll_trailers( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll>, Self::Error>> { + Poll::Ready(Ok(None)) + } +} + +impl SdkBody { + fn poll_inner(&mut self) -> Poll>> { + match self { + SdkBody::Once(ref mut opt) => { + let data = opt.take(); + match data { + Some(bytes) => Poll::Ready(Some(Ok(bytes))), + None => Poll::Ready(None), + } + } + } + } +} + +impl From<&str> for SdkBody { + fn from(s: &str) -> Self { + SdkBody::Once(Some(Bytes::copy_from_slice(s.as_bytes()))) + } +} + +impl From for SdkBody { + fn from(bytes: Bytes) -> Self { + SdkBody::Once(Some(bytes)) + } +} + +impl From> for SdkBody { + fn from(data: Vec) -> SdkBody { + Self::from(Bytes::from(data)) + } +} + +// TODO: consider field privacy, builders, etc. +pub struct Operation { + pub base: http::Request, + + // These could also be attached in as extensions, but explicit might be better. + // Having some explicit configurations as explicit fields doesn't preclude storing data as + // extensions in the future + pub signing_config: SigningConfig, + pub credentials_provider: Box, + pub endpoint_config: Box, + + pub response_handler: Option>, +} + +pub trait HttpRequestResponse { + type O; + /// Parse an HTTP request without reading the body. If the body must be provided to proceed, + /// return `None` + /// + /// This exists to serve APIs like S3::GetObject where the body is passed directly into the + /// response and consumed by the client. However, even in the case of S3::GetObject, errors + /// require reading the entire body. + fn parse_unloaded(&self, response: &mut http::Response) -> Option; + fn parse_loaded(&self, response: &http::Response) -> Self::O; +} From 7f0020d406ca818d47d0d1dd3b9ce41c212597b4 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 12 Jan 2021 18:33:12 -0500 Subject: [PATCH 04/50] Cleanup Rust code --- aws/rust-runtime/auth/src/lib.rs | 8 +- aws/rust-runtime/aws-hyper/src/lib.rs | 91 ++++++++++--------- aws/rust-runtime/operation/src/lib.rs | 3 +- aws/rust-runtime/operation/src/middleware.rs | 17 ++-- .../operation/src/signing_middleware.rs | 6 ++ 5 files changed, 65 insertions(+), 60 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 2a5333f0c1..d087aeab74 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -1,5 +1,5 @@ use std::error::Error; -use std::future::Future; +use std::fmt::{Display, Formatter}; use std::time::{Instant, SystemTime}; /// AWS SDK Credentials @@ -60,7 +60,6 @@ impl Display for CredentialsProviderError { impl Error for CredentialsProviderError {} - // TODO type CredentialsError = Box; @@ -127,11 +126,6 @@ pub struct ServiceConfig { type SigningError = Box; -use std::fmt::{Display, Formatter}; -use std::pin::Pin; -use std::task; -use std::task::Poll; - #[derive(Clone)] pub struct HttpSigner {} diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 3b6756ad00..e2e677c0d7 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,9 +1,9 @@ use bytes::{Buf, Bytes}; -use operation::{HttpRequestResponse, Operation, SdkBody, middleware::OperationError}; +use hyper::Client as HyperClient; +use operation::{middleware::OperationError, HttpRequestResponse, Operation, SdkBody}; use std::error::Error; use tower::util::ReadyOneshot; use tower::{Layer, Service}; -use hyper::{Client as HyperClient}; type ResponseBody = hyper::Body; @@ -30,7 +30,7 @@ impl SdkError { match self { SdkError::DispatchFailure(e) => e, SdkError::ResponseError { err, .. } => err, - SdkError::ServiceError { err, .. } => Box::new(err) + SdkError::ServiceError { err, .. } => Box::new(err), } } } @@ -42,24 +42,24 @@ pub struct Client { impl Client, SdkBody>> { pub fn default() -> Self { let https = HttpsConnector::new(); - let client = HyperClient::builder() - .build::<_, SdkBody>(https); - Client { - inner: client - } + let client = HyperClient::builder().build::<_, SdkBody>(https); + Client { inner: client } } } impl Client - where - S: Service, Response=http::Response> + Clone, - S::Error: std::error::Error + 'static, +where + S: Service, Response = http::Response> + Clone, + S::Error: std::error::Error + 'static, { - pub async fn call(&self, mut input: Operation) -> Result, SdkError> - where + pub async fn call( + &self, + mut input: Operation, + ) -> Result, SdkError> + where // TODO: clean up the way that response handlers work—should they be disconnected from the operation, // at least at this level of the API? - O: HttpRequestResponse>, + O: HttpRequestResponse>, { let ready_service = ReadyOneshot::new(self.inner.clone()) .await @@ -67,14 +67,13 @@ impl Client let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); - let mut ready_service = signer.layer(endpoint_resolver.layer(DispatchLayer.layer(ready_service))); + let mut ready_service = + signer.layer(endpoint_resolver.layer(DispatchLayer.layer(ready_service))); let handler = input.response_handler.take().unwrap(); - let mut response: http::Response = ready_service - .call(input) - .await - .map_err(|e| match e { + let mut response: http::Response = + ready_service.call(input).await.map_err(|e| match e { OperationError::DispatchError(e) => SdkError::DispatchFailure(Box::new(e)), - OperationError::ConstructionError(e) => SdkError::DispatchFailure(e) + OperationError::ConstructionError(e) => SdkError::DispatchFailure(e), })?; let parsed = handler.parse_unloaded(&mut response); @@ -106,7 +105,7 @@ impl Client let response = response.map(|_| Bytes::from(body)); let parsed = handler.parse_loaded(&response); - let raw = response.map(|bytes| hyper::Body::from(bytes)); + let raw = response.map(hyper::Body::from); match parsed { Ok(parsed) => Ok(SdkResponse { raw, parsed }), Err(err) => Err(SdkError::ServiceError { raw, err }), @@ -114,13 +113,12 @@ impl Client } } -use http_body; use http_body::Body; +use hyper::client::HttpConnector; +use hyper_tls::HttpsConnector; +use operation::endpoint::EndpointMiddleware; use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; use operation::signing_middleware::SigningMiddleware; -use operation::endpoint::EndpointMiddleware; -use hyper_tls::HttpsConnector; -use hyper::client::HttpConnector; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -137,18 +135,20 @@ async fn read_body(body: B) -> Result, B::Error> { #[cfg(test)] mod test { - use operation::{Operation, HttpRequestResponse, SdkBody}; - use std::time::SystemTime; - use operation::endpoint::StaticEndpoint; - use http::{Response, Request}; + use crate::{read_body, Client}; + use auth::{ + Credentials, HttpSignatureType, HttpSigningConfig, RequestConfig, ServiceConfig, + SigningAlgorithm, SigningConfig, + }; use bytes::Bytes; - use std::sync::{Arc, Mutex}; + use http::{Request, Response}; use hyper::service::service_fn; - use crate::{read_body, Client}; - use auth::{SigningConfig, HttpSigningConfig, SigningAlgorithm, HttpSignatureType, ServiceConfig, RequestConfig, Credentials}; - use tower::Service; - use std::error::Error; + use operation::endpoint::StaticEndpoint; + use operation::{HttpRequestResponse, Operation, SdkBody}; use pin_utils::core_reexport::fmt::Formatter; + use std::error::Error; + use std::sync::{Arc, Mutex}; + use std::time::SystemTime; #[derive(Clone)] struct TestOperationParser; @@ -166,7 +166,6 @@ mod test { #[tokio::test] async fn e2e_service() { - #[derive(Debug)] struct TestError; @@ -205,17 +204,27 @@ mod test { let http_service = service_fn(|request: Request| async { let mut request = request; let body = read_body(request.body_mut()).await.unwrap(); - *(test_request.clone().lock().unwrap()) = Some(request.map(|_|Bytes::from(body))); - Result::, TestError>::Ok(Response::new(hyper::Body::from("hello!"))) + *(test_request.clone().lock().unwrap()) = Some(request.map(|_| Bytes::from(body))); + Result::, TestError>::Ok(Response::new(hyper::Body::from( + "hello!", + ))) }); //let x: () = http_service; //http_service.call(http::Request::new(SdkBody::from("123"))); - let client = Client { inner: http_service }; + let client = Client { + inner: http_service, + }; let response = client.call(operation).await; let request = test_request.lock().unwrap().take().unwrap(); - assert_eq!(request.headers().keys().map(|it|it.as_str()).collect::>(), vec!["authorization", "x-amz-date"]); + assert_eq!( + request + .headers() + .keys() + .map(|it| it.as_str()) + .collect::>(), + vec!["authorization", "x-amz-date"] + ); assert!(response.is_ok()); - } #[test] @@ -244,6 +253,6 @@ mod test { response_handler: Some(Box::new(TestOperationParser)), }; let client = Client::default(); - let _ = client.call(operation); + let _ = client.call(operation); } } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 0c592a0b8c..569281a5ac 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -7,9 +7,8 @@ pub mod middleware; pub mod signing_middleware; use endpoint::ProvideEndpoint; -use http::{HeaderValue, HeaderMap}; +use http::{HeaderMap, HeaderValue}; use std::error::Error; -use std::fmt::Debug; use std::pin::Pin; use std::task::{Context, Poll}; diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 469c0c6bcc..6217862a80 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -142,9 +142,7 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); - this.f - .poll(cx) - .map_err(|e| OperationError::DispatchError(e)) + this.f.poll(cx).map_err(OperationError::DispatchError) } } @@ -159,7 +157,7 @@ where fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner .poll_ready(cx) - .map_err(|e| OperationError::DispatchError(e)) + .map_err(OperationError::DispatchError) } fn call(&mut self, req: Operation) -> Self::Future { @@ -178,13 +176,12 @@ mod test { Credentials, HttpSignatureType, HttpSigningConfig, RequestConfig, ServiceConfig, SigningAlgorithm, SigningConfig, }; + use bytes::Bytes; use http::header::HeaderName; use http::{HeaderValue, Request, Response}; - use hyper::body::Bytes; - use std::convert::TryInto; use std::error::Error; use std::str::FromStr; - use std::time::{Instant, SystemTime}; + use std::time::SystemTime; use tower::service_fn; use tower::{Layer, Service}; @@ -192,11 +189,11 @@ mod test { impl HttpRequestResponse for TestOperationParser { type O = String; - fn parse_unloaded(&self, response: &mut Response) -> Option { + fn parse_unloaded(&self, _response: &mut Response) -> Option { Some("Hello!".to_string()) } - fn parse_loaded(&self, response: &Response) -> Self::O { + fn parse_loaded(&self, _response: &Response) -> Self::O { "Hello!".to_string() } } @@ -254,7 +251,7 @@ mod test { }), credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - response_handler: Box::new(TestOperationParser), + response_handler: Some(Box::new(TestOperationParser)), }; let response = service.call(operation).await; assert_eq!(response.unwrap().body(), "x-key:\"X-Key\""); diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 9d68a93064..28539b2a07 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -13,6 +13,12 @@ pub struct SigningMiddleware { signer: HttpSigner, } +impl Default for SigningMiddleware { + fn default() -> Self { + SigningMiddleware::new() + } +} + impl SigningMiddleware { pub fn new() -> Self { SigningMiddleware { From 832886aab0401addfde6611c637725f0a248b752 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Thu, 14 Jan 2021 11:14:34 -0500 Subject: [PATCH 05/50] Refactor operation to split input and reponse handler --- aws/rust-runtime/aws-hyper/src/lib.rs | 83 ++++++++++--------- aws/rust-runtime/operation/src/endpoint.rs | 21 +++-- aws/rust-runtime/operation/src/lib.rs | 14 +++- aws/rust-runtime/operation/src/middleware.rs | 30 +++---- .../operation/src/signing_middleware.rs | 5 +- 5 files changed, 84 insertions(+), 69 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index e2e677c0d7..7292cf2836 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,9 +1,9 @@ use bytes::{Buf, Bytes}; use hyper::Client as HyperClient; -use operation::{middleware::OperationError, HttpRequestResponse, Operation, SdkBody}; +use operation::{middleware::OperationError, Operation, ParseHttpResponse, SdkBody}; use std::error::Error; use tower::util::ReadyOneshot; -use tower::{Layer, Service}; +use tower::{Service, ServiceBuilder}; type ResponseBody = hyper::Body; @@ -52,14 +52,9 @@ where S: Service, Response = http::Response> + Clone, S::Error: std::error::Error + 'static, { - pub async fn call( - &self, - mut input: Operation, - ) -> Result, SdkError> + pub async fn call(&self, input: Operation) -> Result, SdkError> where - // TODO: clean up the way that response handlers work—should they be disconnected from the operation, - // at least at this level of the API? - O: HttpRequestResponse>, + O: ParseHttpResponse>, { let ready_service = ReadyOneshot::new(self.inner.clone()) .await @@ -67,11 +62,17 @@ where let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); - let mut ready_service = - signer.layer(endpoint_resolver.layer(DispatchLayer.layer(ready_service))); - let handler = input.response_handler.take().unwrap(); - let mut response: http::Response = - ready_service.call(input).await.map_err(|e| match e { + let mut ready_service = ServiceBuilder::new() + .layer(signer) + .layer(endpoint_resolver) + .layer(DispatchLayer) + .service(ready_service); + // TODO: enable operations to specify their own extra middleware to add + let handler = input.response_handler; + let mut response: http::Response = ready_service + .call(input.request) + .await + .map_err(|e| match e { OperationError::DispatchError(e) => SdkError::DispatchFailure(Box::new(e)), OperationError::ConstructionError(e) => SdkError::DispatchFailure(e), })?; @@ -144,7 +145,7 @@ mod test { use http::{Request, Response}; use hyper::service::service_fn; use operation::endpoint::StaticEndpoint; - use operation::{HttpRequestResponse, Operation, SdkBody}; + use operation::{Operation, ParseHttpResponse, SdkBody}; use pin_utils::core_reexport::fmt::Formatter; use std::error::Error; use std::sync::{Arc, Mutex}; @@ -152,7 +153,7 @@ mod test { #[derive(Clone)] struct TestOperationParser; - impl HttpRequestResponse for TestOperationParser { + impl ParseHttpResponse for TestOperationParser { type O = Result; fn parse_unloaded(&self, _response: &mut Response) -> Option { @@ -177,27 +178,32 @@ mod test { impl Error for TestError {}; let operation = Operation { - base: Request::builder() - .uri("/some_url") - .body(SdkBody::from("Hello")) - .unwrap(), - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - service: "svc".to_string(), - region: "region".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), - }, - double_uri_encode: false, - normalize_uri_path: true, - omit_session_token: false, - }), - credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), - endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - response_handler: Some(Box::new(TestOperationParser)), + request: operation::Request { + base: Request::builder() + .uri("/some_url") + .body(SdkBody::from("Hello")) + .unwrap(), + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + service: "svc".to_string(), + region: "region".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + }), + credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), + endpoint_config: Box::new(StaticEndpoint::from_service_region( + "dynamodb", + "us-east-1", + )), + }, + response_handler: Box::new(TestOperationParser), }; let test_request: Arc>>> = Arc::new(Mutex::new(None)); @@ -227,6 +233,7 @@ mod test { assert!(response.is_ok()); } + /* #[test] fn real_service() { let operation = Operation { @@ -254,5 +261,5 @@ mod test { }; let client = Client::default(); let _ = client.call(operation); - } + }*/ } diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index e40416106f..d5401e51c0 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -3,13 +3,14 @@ * SPDX-License-Identifier: Apache-2.0. */ -use crate::middleware::OperationMiddleware; -use crate::Operation; use core::convert::AsRef; -use http::uri::Uri; use std::error::Error; use std::str::FromStr; +use http::uri::Uri; + +use crate::middleware::OperationMiddleware; + pub struct StaticEndpoint(http::Uri); impl StaticEndpoint { @@ -54,11 +55,11 @@ impl ProvideEndpoint for StaticEndpoint { } } -impl OperationMiddleware for T +impl OperationMiddleware for T where T: ProvideEndpoint, { - fn apply(&self, request: &mut Operation) -> Result<(), Box> { + fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { self.set_endpoint(&mut request.base.uri_mut()); Ok(()) } @@ -68,8 +69,8 @@ where #[derive(Clone, Copy)] /// Set the endpoint for a request based on the endpoint config pub struct EndpointMiddleware; -impl OperationMiddleware for EndpointMiddleware { - fn apply(&self, request: &mut Operation) -> Result<(), Box> { +impl OperationMiddleware for EndpointMiddleware { + fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { let endpoint_config = &request.endpoint_config; endpoint_config.set_endpoint(&mut request.base.uri_mut()); Ok(()) @@ -78,10 +79,12 @@ impl OperationMiddleware for EndpointMiddleware { #[cfg(test)] mod test { - use crate::endpoint::StaticEndpoint; - use http::Uri; use std::str::FromStr; + use http::Uri; + + use crate::endpoint::StaticEndpoint; + #[test] fn endpoint_from_svc() { let endpoint = StaticEndpoint::from_service_region("dynamodb", "us-west-2"); diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 569281a5ac..b856ab8cf6 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -71,6 +71,11 @@ impl From> for SdkBody { // TODO: consider field privacy, builders, etc. pub struct Operation { + pub request: Request, + pub response_handler: Box, +} + +pub struct Request { pub base: http::Request, // These could also be attached in as extensions, but explicit might be better. @@ -79,11 +84,9 @@ pub struct Operation { pub signing_config: SigningConfig, pub credentials_provider: Box, pub endpoint_config: Box, - - pub response_handler: Option>, } -pub trait HttpRequestResponse { +pub trait ParseHttpResponse { type O; /// Parse an HTTP request without reading the body. If the body must be provided to proceed, /// return `None` @@ -91,6 +94,9 @@ pub trait HttpRequestResponse { /// This exists to serve APIs like S3::GetObject where the body is passed directly into the /// response and consumed by the client. However, even in the case of S3::GetObject, errors /// require reading the entire body. - fn parse_unloaded(&self, response: &mut http::Response) -> Option; + fn parse_unloaded( + &self, + response: &mut http::Response, + ) -> Option; fn parse_loaded(&self, response: &http::Response) -> Self::O; } diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 6217862a80..4a5c1f7647 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -3,15 +3,15 @@ * SPDX-License-Identifier: Apache-2.0. */ -use crate::{Operation, SdkBody}; +use crate::SdkBody; use std::error::Error; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use tower::{Layer, Service}; -pub trait OperationMiddleware { - fn apply(&self, request: &mut Operation) -> Result<(), Box>; +pub trait OperationMiddleware { + fn apply(&self, request: &mut crate::Request) -> Result<(), Box>; } pub struct OperationRequestMiddlewareService { @@ -67,10 +67,10 @@ where } } -impl Service> for OperationRequestMiddlewareService +impl Service for OperationRequestMiddlewareService where - S: Service>, - M: OperationMiddleware, + S: Service, + M: OperationMiddleware, S::Error: RequestConstructionErr, { type Response = S::Response; @@ -81,7 +81,7 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, mut req: Operation) -> Self::Future { + fn call(&mut self, mut req: crate::Request) -> Self::Future { if let Err(e) = self .middleware .apply(&mut req) @@ -146,7 +146,7 @@ where } } -impl Service> for DispatchMiddleware +impl Service for DispatchMiddleware where S: Service>, { @@ -160,7 +160,7 @@ where .map_err(OperationError::DispatchError) } - fn call(&mut self, req: Operation) -> Self::Future { + fn call(&mut self, req: crate::Request) -> Self::Future { OperationFuture { f: self.inner.call(req.base), } @@ -171,7 +171,7 @@ where mod test { use crate::endpoint::StaticEndpoint; use crate::middleware::{DispatchLayer, OperationMiddleware, OperationRequestMiddlewareLayer}; - use crate::{HttpRequestResponse, Operation, SdkBody}; + use crate::{ParseHttpResponse, SdkBody}; use auth::{ Credentials, HttpSignatureType, HttpSigningConfig, RequestConfig, ServiceConfig, SigningAlgorithm, SigningConfig, @@ -186,7 +186,8 @@ mod test { use tower::{Layer, Service}; struct TestOperationParser; - impl HttpRequestResponse for TestOperationParser { + + impl ParseHttpResponse for TestOperationParser { type O = String; fn parse_unloaded(&self, _response: &mut Response) -> Option { @@ -202,8 +203,8 @@ mod test { async fn middleware_test() { #[derive(Clone)] struct AddHeader(String, String); - impl OperationMiddleware for AddHeader { - fn apply(&self, request: &mut Operation) -> Result<(), Box> { + impl OperationMiddleware for AddHeader { + fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { request.base.headers_mut().append( HeaderName::from_str(&self.0).unwrap(), HeaderValue::from_str(&self.0).unwrap(), @@ -230,7 +231,7 @@ mod test { } }); let mut service = add_header.layer(DispatchLayer.layer(http_service)); - let operation = Operation { + let operation = crate::Request { base: Request::builder() .uri("/some_url") .body(SdkBody::from("Hello")) @@ -251,7 +252,6 @@ mod test { }), credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - response_handler: Some(Box::new(TestOperationParser)), }; let response = service.call(operation).await; assert_eq!(response.unwrap().body(), "x-key:\"X-Key\""); diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 28539b2a07..d7ba1b02fe 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0. */ use crate::middleware::OperationMiddleware; -use crate::Operation; use crate::SdkBody; use auth::{HttpSigner, SigningConfig}; use std::error::Error; @@ -27,8 +26,8 @@ impl SigningMiddleware { } } -impl OperationMiddleware for SigningMiddleware { - fn apply(&self, request: &mut Operation) -> Result<(), Box> { +impl OperationMiddleware for SigningMiddleware { + fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { let signing_config = &request.signing_config; let creds = request.credentials_provider.credentials()?; let body = match request.base.body() { From 53045153bb1c8ea59980cb502b33b682c4119d4e Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Thu, 14 Jan 2021 12:55:51 -0500 Subject: [PATCH 06/50] Improve parse response traits --- aws/rust-runtime/aws-hyper/src/lib.rs | 13 +++-- aws/rust-runtime/operation/src/lib.rs | 33 +++++++++--- aws/rust-runtime/operation/src/middleware.rs | 11 ++-- aws/sdk/dynamo-it/src/main.rs | 53 +++++++++----------- 4 files changed, 65 insertions(+), 45 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 7292cf2836..752aed6b52 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -54,7 +54,7 @@ where { pub async fn call(&self, input: Operation) -> Result, SdkError> where - O: ParseHttpResponse>, + O: ParseHttpResponse>, { let ready_service = ReadyOneshot::new(self.inner.clone()) .await @@ -153,14 +153,17 @@ mod test { #[derive(Clone)] struct TestOperationParser; - impl ParseHttpResponse for TestOperationParser { - type O = Result; + impl ParseHttpResponse for TestOperationParser + where + B: http_body::Body, + { + type Output = Result; - fn parse_unloaded(&self, _response: &mut Response) -> Option { + fn parse_unloaded(&self, _response: &mut Response) -> Option { Some(Ok("Hello!".to_string())) } - fn parse_loaded(&self, _response: &Response) -> Self::O { + fn parse_loaded(&self, _response: &Response) -> Self::Output { Ok("Hello!".to_string()) } } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index b856ab8cf6..e8cc70f2a8 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -7,7 +7,7 @@ pub mod middleware; pub mod signing_middleware; use endpoint::ProvideEndpoint; -use http::{HeaderMap, HeaderValue}; +use http::{HeaderMap, HeaderValue, Response}; use std::error::Error; use std::pin::Pin; use std::task::{Context, Poll}; @@ -86,17 +86,34 @@ pub struct Request { pub endpoint_config: Box, } -pub trait ParseHttpResponse { - type O; +pub trait ParseHttpResponse { + type Output; /// Parse an HTTP request without reading the body. If the body must be provided to proceed, /// return `None` /// /// This exists to serve APIs like S3::GetObject where the body is passed directly into the /// response and consumed by the client. However, even in the case of S3::GetObject, errors /// require reading the entire body. - fn parse_unloaded( - &self, - response: &mut http::Response, - ) -> Option; - fn parse_loaded(&self, response: &http::Response) -> Self::O; + fn parse_unloaded(&self, response: &mut http::Response) -> Option; + fn parse_loaded(&self, response: &http::Response) -> Self::Output; +} + +pub trait ParseStrictResponse { + type Output; + fn parse(&self, response: &Response) -> Self::Output; +} + +impl ParseHttpResponse for T +where + T: ParseStrictResponse, +{ + type Output = T::Output; + + fn parse_unloaded(&self, _response: &mut Response) -> Option { + None + } + + fn parse_loaded(&self, response: &Response) -> Self::Output { + self.parse(response) + } } diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 4a5c1f7647..d7c028e0bf 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -187,14 +187,17 @@ mod test { struct TestOperationParser; - impl ParseHttpResponse for TestOperationParser { - type O = String; + impl ParseHttpResponse for TestOperationParser + where + B: http_body::Body, + { + type Output = String; - fn parse_unloaded(&self, _response: &mut Response) -> Option { + fn parse_unloaded(&self, _response: &mut Response) -> Option { Some("Hello!".to_string()) } - fn parse_loaded(&self, _response: &Response) -> Self::O { + fn parse_loaded(&self, _response: &Response) -> Self::Output { "Hello!".to_string() } } diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index 794fcd551b..4f77cb1b4c 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -10,7 +10,7 @@ use dynamodb::model::{ }; use dynamodb::operation::CreateTable; use dynamodb::output::{ListTablesOutput, DeleteTableOutput}; -use operation::{HttpRequestResponse, SdkBody, Operation}; +use operation::{HttpRequestResponse, SdkBody, Operation, ParseStrictResponse, Request}; use dynamodb::error::DeleteTableError; struct DeleteTable(dynamodb::operation::DeleteTable); @@ -21,14 +21,9 @@ use std::time::SystemTime; use operation::endpoint::StaticEndpoint; use http::{Response, Uri}; -impl HttpRequestResponse for DeleteTable { - type O = Result; - - fn parse_unloaded(&self, _: &mut Response) -> Option { - None - } - - fn parse_loaded(&self, response: &Response) -> Self::O { +impl ParseStrictResponse for DeleteTable { + type Output = Result; + fn parse(&self, response: &Response) -> Self::O { self.0.parse_response(response) } } @@ -36,25 +31,27 @@ impl HttpRequestResponse for DeleteTable { impl DeleteTable { fn into_operation(self, config: dynamodb::Config) -> Operation { Operation { - base: self.0.build_http_request().map(|body|SdkBody::from(body)), - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - // TODO: these get loaded from the config - service: "dynamodb".to_string(), - region: "us-east-1".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), - }, - double_uri_encode: false, - normalize_uri_path: true, - omit_session_token: false, - }), - credentials_provider: config.credentials_provider, - endpoint_config: Box::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))), - response_handler: Some(Box::new(self)), + request: Request { + base: self.0.build_http_request().map(|body| SdkBody::from(body)), + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + // TODO: these get loaded from the config + service: "dynamodb".to_string(), + region: "us-east-1".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + }), + credentials_provider: config.credentials_provider, + endpoint_config: Box::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))), + }, + response_handler: Box::new(self), } } } From c5856ec9e6c5e086b13629396768efd3d41f8a83 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 15 Jan 2021 11:36:16 -0500 Subject: [PATCH 07/50] creds experimentation --- aws/rust-runtime/auth/src/lib.rs | 32 +++++++++--------- aws/sdk/dynamo-it/Cargo.lock | 1 + aws/sdk/dynamo-it/Cargo.toml | 1 + aws/sdk/dynamo-it/src/main.rs | 57 +++++++++++++------------------- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index d087aeab74..163aa249ac 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -1,6 +1,7 @@ use std::error::Error; use std::fmt::{Display, Formatter}; use std::time::{Instant, SystemTime}; +use std::borrow::Cow; /// AWS SDK Credentials /// @@ -30,15 +31,14 @@ pub struct Credentials { impl Credentials { /// Create a Credentials struct from static credentials - pub fn from_static( - access_key_id: T, - secret_access_key: T, - session_token: Option, + pub fn from_static( + access_key_id: impl ToString, + secret_access_key: impl ToString, ) -> Self { Credentials { access_key_id: access_key_id.to_string(), secret_access_key: secret_access_key.to_string(), - session_token: session_token.map(|tok| tok.to_string()), + session_token: None, expiration: None, } } @@ -75,7 +75,7 @@ pub trait ProvideCredentials { pub fn default_provider() -> impl ProvideCredentials { // todo: this should be a chain, maybe CRT? // Determine what the minimum support is - Credentials::from_static("todo", "todo", None) + Credentials::from_static("todo", "todo") } impl ProvideCredentials for Credentials { @@ -120,8 +120,8 @@ pub struct RequestConfig { } pub struct ServiceConfig { - pub service: String, - pub region: String, + pub service: Cow<'static, str>, + pub region: Cow<'static, str>, } type SigningError = Box; @@ -187,19 +187,19 @@ mod test { struct DynamoConfig { signer: HttpSigner, credentials_provider: Box, - service: String, - region: String, + service: &'static str, + region: &'static str, time_source: fn() -> SystemTime, } impl DynamoConfig { pub fn from_env() -> Self { - let stub_creds = Credentials::from_static("asdf", "asef", None); + let stub_creds = Credentials::from_static("asdf", "asef"); DynamoConfig { signer: HttpSigner {}, credentials_provider: Box::new(stub_creds), - service: "dynamodb".to_string(), - region: "us-east-1".to_string(), + service: "dynamodb", + region: "us-east-1", time_source: || SystemTime::now(), } } @@ -213,6 +213,8 @@ mod test { input: ListTablesOperationInput, } + use std::borrow::Cow; + impl ListTablesOperation { pub fn raw_request( &self, @@ -229,8 +231,8 @@ mod test { } pub async fn finalize(config: &DynamoConfig, mut request: &mut http::Request>) { let service_config = ServiceConfig { - service: config.service.clone(), - region: config.region.clone(), + service: Cow::Borrowed(config.service), + region: Cow::Borrowed(config.region), }; let signing_config = ListTablesOperation::signing_config( RequestConfig { diff --git a/aws/sdk/dynamo-it/Cargo.lock b/aws/sdk/dynamo-it/Cargo.lock index 17182c046b..8e4e3fea85 100644 --- a/aws/sdk/dynamo-it/Cargo.lock +++ b/aws/sdk/dynamo-it/Cargo.lock @@ -150,6 +150,7 @@ dependencies = [ "bytes 1.0.0", "dynamodb", "http", + "hyper 0.14.2", "io-v0", "operation", "rand 0.7.3", diff --git a/aws/sdk/dynamo-it/Cargo.toml b/aws/sdk/dynamo-it/Cargo.toml index 5885ccbe83..43b07f24f1 100644 --- a/aws/sdk/dynamo-it/Cargo.toml +++ b/aws/sdk/dynamo-it/Cargo.toml @@ -14,6 +14,7 @@ aws-hyper = { path = "../build/aws-sdk/aws-hyper"} tokio = { version = "1", features = ["full"] } rand = "0.7.3" bytes = "1" +hyper = "0.14.2" # these are just for the stub implementation diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index 4f77cb1b4c..9f74fb261a 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -5,25 +5,24 @@ use std::error::Error; -use dynamodb::model::{ - AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, -}; -use dynamodb::operation::CreateTable; -use dynamodb::output::{ListTablesOutput, DeleteTableOutput}; -use operation::{HttpRequestResponse, SdkBody, Operation, ParseStrictResponse, Request}; +use dynamodb::output::{DeleteTableOutput, ListTablesOutput}; +use operation::{SdkBody, Operation, ParseStrictResponse, Request}; use dynamodb::error::DeleteTableError; struct DeleteTable(dynamodb::operation::DeleteTable); -use bytes::Bytes; -use auth::{SigningConfig, HttpSigningConfig, SigningAlgorithm, HttpSignatureType, ServiceConfig, RequestConfig}; -use std::time::SystemTime; -use operation::endpoint::StaticEndpoint; +//use bytes::Bytes; +//use auth::{SigningConfig, ServiceConfig, RequestConfig}; +//use std::time::SystemTime; +//use operation::endpoint::StaticEndpoint; use http::{Response, Uri}; +use dynamodb::operation::CreateTable; +use dynamodb::model::{AttributeDefinition, ScalarAttributeType, KeySchemaElement, ProvisionedThroughput, KeyType}; +/* impl ParseStrictResponse for DeleteTable { type Output = Result; - fn parse(&self, response: &Response) -> Self::O { + fn parse(&self, response: &Response) -> Self::Output { self.0.parse_response(response) } } @@ -33,45 +32,35 @@ impl DeleteTable { Operation { request: Request { base: self.0.build_http_request().map(|body| SdkBody::from(body)), - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - // TODO: these get loaded from the config - service: "dynamodb".to_string(), - region: "us-east-1".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), + signing_config: SigningConfig::default_configuration( + RequestConfig { + request_ts: ||SystemTime::now() }, - double_uri_encode: false, - normalize_uri_path: true, - omit_session_token: false, - }), + ServiceConfig { + service: "dynamodb".into(), + region: "us-east-1".into() + } + ), credentials_provider: config.credentials_provider, endpoint_config: Box::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))), }, response_handler: Box::new(self), } } -} +}*/ #[tokio::main] async fn main() -> Result<(), Box> { let table_name = "new_table"; - let client = aws_hyper::Client::default(); + //let client = aws_hyper::Client::default(); + let client = io_v0::Client::local("dynamodb"); let config = dynamodb::Config::builder().build(); let clear_table = dynamodb::operation::DeleteTable::builder() .table_name(table_name) .build(&config); - let clear_table = DeleteTable(clear_table); - match client.call(clear_table.into_operation(config)).await { - Ok(response) => println!("OK! {:?}", response.parsed), - Err(_response) => println!("failure: {}", _response.error()) - } - /* + match io_v0::dispatch!(client, clear_table).parsed() { Ok(Ok(table_deleted)) => println!( "{:?} was deleted", @@ -144,7 +133,7 @@ async fn main() -> Result<(), Box> { ListTablesOutput::builder() .table_names(vec![table_name.to_string()]) .build() - );*/ + ); Ok(()) } From bb50baf53ad4849e3569ba0a47a09de829b6ba0b Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 15 Jan 2021 16:11:56 -0500 Subject: [PATCH 08/50] wip --- aws/rust-runtime/auth/src/lib.rs | 2 +- aws/rust-runtime/operation/src/endpoint.rs | 7 +- aws/rust-runtime/operation/src/extensions.rs | 187 ++++++++++++++++++ aws/rust-runtime/operation/src/lib.rs | 41 +++- aws/rust-runtime/operation/src/middleware.rs | 7 +- .../operation/src/signing_middleware.rs | 7 +- aws/sdk/dynamo-it/src/main.rs | 37 ++-- 7 files changed, 257 insertions(+), 31 deletions(-) create mode 100644 aws/rust-runtime/operation/src/extensions.rs diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 163aa249ac..d7e8685050 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -68,7 +68,7 @@ type CredentialsError = Box; /// Credentials providers may be sync or async, they may cache credentials, etc. /// /// WARNING: This interface is unstable pending async traits -pub trait ProvideCredentials { +pub trait ProvideCredentials: Send + Sync { fn credentials(&self) -> Result; } diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index d5401e51c0..67e8f4ba1f 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -44,7 +44,7 @@ impl StaticEndpoint { } } -pub trait ProvideEndpoint { +pub trait ProvideEndpoint: Send + Sync { fn set_endpoint(&self, request_uri: &mut Uri); } @@ -71,8 +71,9 @@ where pub struct EndpointMiddleware; impl OperationMiddleware for EndpointMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let endpoint_config = &request.endpoint_config; - endpoint_config.set_endpoint(&mut request.base.uri_mut()); + let extensions = &request.extensions; + let endpoint_provider: &Box = extensions.get().unwrap(); + endpoint_provider.set_endpoint(&mut request.base.uri_mut()); Ok(()) } } diff --git a/aws/rust-runtime/operation/src/extensions.rs b/aws/rust-runtime/operation/src/extensions.rs new file mode 100644 index 0000000000..6d398c27ab --- /dev/null +++ b/aws/rust-runtime/operation/src/extensions.rs @@ -0,0 +1,187 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +// Adapted from Hyper Extensions +use std::any::{Any, TypeId}; +use std::collections::HashMap; +use std::fmt; +use std::hash::{BuildHasherDefault, Hasher}; + +type AnyMap = HashMap, BuildHasherDefault>; + +// With TypeIds as keys, there's no need to hash them. They are already hashes +// themselves, coming from the compiler. The IdHasher just holds the u64 of +// the TypeId, and then returns it, instead of doing any bit fiddling. +#[derive(Default)] +struct IdHasher(u64); + +impl Hasher for IdHasher { + #[inline] + fn finish(&self) -> u64 { + self.0 + } + + fn write(&mut self, _: &[u8]) { + unreachable!("TypeId calls write_u64"); + } + + #[inline] + fn write_u64(&mut self, id: u64) { + self.0 = id; + } +} + +/// A type map of protocol extensions. +/// +/// `Extensions` can be used by `Request` and `Response` to store +/// extra data derived from the underlying protocol. +#[derive(Default)] +pub struct Extensions { + // If extensions are never used, no need to carry around an empty HashMap. + // That's 3 words. Instead, this is only 1 word. + map: Option>, +} + +impl Extensions { + /// Create an empty `Extensions`. + #[inline] + pub fn new() -> Extensions { + Extensions { map: None } + } + + /// Insert a type into this `Extensions`. + /// + /// If a extension of this type already existed, it will + /// be returned. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// assert!(ext.insert(5i32).is_none()); + /// assert!(ext.insert(4u8).is_none()); + /// assert_eq!(ext.insert(9i32), Some(5i32)); + /// ``` + pub fn insert(&mut self, val: T) -> Option { + self.map + .get_or_insert_with(|| Box::new(HashMap::default())) + .insert(TypeId::of::(), Box::new(val)) + .and_then(|boxed| { + (boxed as Box) + .downcast() + .ok() + .map(|boxed| *boxed) + }) + } + + /// Get a reference to a type previously inserted on this `Extensions`. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// assert!(ext.get::().is_none()); + /// ext.insert(5i32); + /// + /// assert_eq!(ext.get::(), Some(&5i32)); + /// ``` + pub fn get(&self) -> Option<&T> { + self.map + .as_ref() + .and_then(|map| map.get(&TypeId::of::())) + .and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref()) + } + + /// Get a mutable reference to a type previously inserted on this `Extensions`. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// ext.insert(String::from("Hello")); + /// ext.get_mut::().unwrap().push_str(" World"); + /// + /// assert_eq!(ext.get::().unwrap(), "Hello World"); + /// ``` + pub fn get_mut(&mut self) -> Option<&mut T> { + self.map + .as_mut() + .and_then(|map| map.get_mut(&TypeId::of::())) + .and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut()) + } + + /// Remove a type from this `Extensions`. + /// + /// If a extension of this type existed, it will be returned. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// ext.insert(5i32); + /// assert_eq!(ext.remove::(), Some(5i32)); + /// assert!(ext.get::().is_none()); + /// ``` + pub fn remove(&mut self) -> Option { + self.map + .as_mut() + .and_then(|map| map.remove(&TypeId::of::())) + .and_then(|boxed| { + (boxed as Box) + .downcast() + .ok() + .map(|boxed| *boxed) + }) + } + + /// Clear the `Extensions` of all inserted extensions. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// ext.insert(5i32); + /// ext.clear(); + /// + /// assert!(ext.get::().is_none()); + /// ``` + #[inline] + pub fn clear(&mut self) { + if let Some(ref mut map) = self.map { + map.clear(); + } + } +} + +impl fmt::Debug for Extensions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Extensions").finish() + } +} + +#[test] +fn test_extensions() { + #[derive(Debug, PartialEq)] + struct MyType(i32); + + let mut extensions = Extensions::new(); + + extensions.insert(5i32); + extensions.insert(MyType(10)); + + assert_eq!(extensions.get(), Some(&5i32)); + assert_eq!(extensions.get_mut(), Some(&mut 5i32)); + + assert_eq!(extensions.remove::(), Some(5i32)); + assert!(extensions.get::().is_none()); + + assert_eq!(extensions.get::(), None); + assert_eq!(extensions.get(), Some(&MyType(10))); +} diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index e8cc70f2a8..00655b1c5b 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -5,12 +5,15 @@ use auth::{ProvideCredentials, SigningConfig}; pub mod endpoint; pub mod middleware; pub mod signing_middleware; +mod extensions; use endpoint::ProvideEndpoint; use http::{HeaderMap, HeaderValue, Response}; use std::error::Error; use std::pin::Pin; use std::task::{Context, Poll}; +use std::sync::{Arc, Mutex}; +use crate::extensions::Extensions; type BodyError = Box; @@ -78,12 +81,44 @@ pub struct Operation { pub struct Request { pub base: http::Request, + pub extensions: Extensions, + // These could also be attached in as extensions, but explicit might be better. // Having some explicit configurations as explicit fields doesn't preclude storing data as // extensions in the future - pub signing_config: SigningConfig, - pub credentials_provider: Box, - pub endpoint_config: Box, + // pub signing_config: SigningConfig, + // pub credentials_provider: Box, + // pub endpoint_config: Box, +} + +impl Request { + + pub fn new(base: http::Request) -> Self { + Request { + base, + extensions: Extensions::new() + } + } + + pub fn signing_config(&self) -> &SigningConfig { + self.extensions.get().unwrap() + } + + pub fn credentials_provider(&self) -> &Box { + self.extensions.get().unwrap() + } + + pub fn endpoint_provider(&self) -> &Box { + self.extensions.get().unwrap() + } + + pub fn request_mut(&mut self) -> &mut http::Request { + &mut self.base + } + + pub fn add_config(&mut self, val: T) -> Option { + self.extensions.insert(val) + } } pub trait ParseHttpResponse { diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index d7c028e0bf..9f5f402389 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -234,11 +234,10 @@ mod test { } }); let mut service = add_header.layer(DispatchLayer.layer(http_service)); - let operation = crate::Request { - base: Request::builder() + let operation = crate::Request::new(Request::builder() .uri("/some_url") .body(SdkBody::from("Hello")) - .unwrap(), + .unwrap()); /*, signing_config: SigningConfig::Http(HttpSigningConfig { algorithm: SigningAlgorithm::SigV4, signature_type: HttpSignatureType::HttpRequestHeaders, @@ -255,7 +254,7 @@ mod test { }), credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - }; + };*/ let response = service.call(operation).await; assert_eq!(response.unwrap().body(), "x-key:\"X-Key\""); } diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index d7ba1b02fe..7d1298914e 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -4,7 +4,7 @@ */ use crate::middleware::OperationMiddleware; use crate::SdkBody; -use auth::{HttpSigner, SigningConfig}; +use auth::{HttpSigner, SigningConfig, ProvideCredentials}; use std::error::Error; #[derive(Clone)] @@ -28,8 +28,9 @@ impl SigningMiddleware { impl OperationMiddleware for SigningMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let signing_config = &request.signing_config; - let creds = request.credentials_provider.credentials()?; + let signing_config = request.extensions.get::().unwrap(); + let cred_provider: &Box = request.extensions.get().unwrap(); + let creds = cred_provider.credentials()?; let body = match request.base.body() { SdkBody::Once(Some(bytes)) => bytes.clone(), SdkBody::Once(None) => bytes::Bytes::new(), diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index 9f74fb261a..4b13e0d1e5 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -18,8 +18,11 @@ struct DeleteTable(dynamodb::operation::DeleteTable); use http::{Response, Uri}; use dynamodb::operation::CreateTable; use dynamodb::model::{AttributeDefinition, ScalarAttributeType, KeySchemaElement, ProvisionedThroughput, KeyType}; +use bytes::Bytes; +use auth::{RequestConfig, ServiceConfig}; +use std::time::SystemTime; + -/* impl ParseStrictResponse for DeleteTable { type Output = Result; fn parse(&self, response: &Response) -> Self::Output { @@ -27,27 +30,27 @@ impl ParseStrictResponse for DeleteTable { } } +use auth::SigningConfig; + impl DeleteTable { fn into_operation(self, config: dynamodb::Config) -> Operation { - Operation { - request: Request { - base: self.0.build_http_request().map(|body| SdkBody::from(body)), - signing_config: SigningConfig::default_configuration( - RequestConfig { - request_ts: ||SystemTime::now() - }, - ServiceConfig { - service: "dynamodb".into(), - region: "us-east-1".into() - } - ), - credentials_provider: config.credentials_provider, - endpoint_config: Box::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))), + let mut request = operation::Request::new(self.0.build_http_request().map(|body|SdkBody::from(body))); + request.extensions.insert(SigningConfig::default_configuration( + RequestConfig { + request_ts: ||SystemTime::now() }, - response_handler: Box::new(self), + ServiceConfig { + service: "dynamodb".into(), + region: "us-east-1".into() + } + )); + request.extensions.insert(config.credentials_provider); + Operation { + request, + response_handler: Box::new(self) } } -}*/ +} #[tokio::main] From 39d8e1abef92b624d62236b788dc7ed13e38169d Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 15 Jan 2021 17:04:25 -0500 Subject: [PATCH 09/50] Migrate request to use extensions instead of specific fields --- aws/rust-runtime/auth/src/lib.rs | 26 +++-- aws/rust-runtime/operation/src/endpoint.rs | 27 ++++- aws/rust-runtime/operation/src/extensions.rs | 10 ++ aws/rust-runtime/operation/src/lib.rs | 32 +----- aws/rust-runtime/operation/src/middleware.rs | 40 +++---- .../operation/src/signing_middleware.rs | 50 ++++++++- .../rustsdk/CredentialProviderConfig.kt | 8 +- aws/sdk/dynamo-it/src/main.rs | 104 ++++-------------- 8 files changed, 149 insertions(+), 148 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index d7e8685050..407fe82039 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -1,7 +1,7 @@ +use std::borrow::Cow; use std::error::Error; use std::fmt::{Display, Formatter}; use std::time::{Instant, SystemTime}; -use std::borrow::Cow; /// AWS SDK Credentials /// @@ -23,18 +23,14 @@ pub struct Credentials { /// /// If these credentials never expire, this value will be set to `None` /// - /// TODO: consider if `Instant` is the best representation—other options: - /// - SystemTime, we don't need monotonicity for this + /// TODO: consider if `SystemTime` is the best representation—other options: /// - u64 - expiration: Option, + expiration: Option, } impl Credentials { /// Create a Credentials struct from static credentials - pub fn from_static( - access_key_id: impl ToString, - secret_access_key: impl ToString, - ) -> Self { + pub fn from_static(access_key_id: impl ToString, secret_access_key: impl ToString) -> Self { Credentials { access_key_id: access_key_id.to_string(), secret_access_key: secret_access_key.to_string(), @@ -103,6 +99,20 @@ pub enum SigningConfig { // Event Stream } +impl SigningConfig { + pub fn default_config(service_config: ServiceConfig, request_config: RequestConfig) -> Self { + SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config, + request_config, + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + }) + } +} + pub struct HttpSigningConfig { pub algorithm: SigningAlgorithm, pub signature_type: HttpSignatureType, diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index 67e8f4ba1f..1de1fde227 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -10,6 +10,8 @@ use std::str::FromStr; use http::uri::Uri; use crate::middleware::OperationMiddleware; +use std::sync::Arc; +use crate::extensions::Extensions; pub struct StaticEndpoint(http::Uri); @@ -65,14 +67,35 @@ where } } + +pub trait EndpointProviderExt { + fn endpoint_provider(&self) -> Option<&Arc>; + fn insert_endpoint_provider( + &mut self, + provider: Arc, + ) -> Option>; +} + +impl EndpointProviderExt for Extensions { + fn endpoint_provider(&self) -> Option<&Arc> { + self.get() + } + + fn insert_endpoint_provider( + &mut self, + provider: Arc, + ) -> Option> { + self.insert(provider) + } +} + // TODO: this should probably move to a collection of middlewares #[derive(Clone, Copy)] /// Set the endpoint for a request based on the endpoint config pub struct EndpointMiddleware; impl OperationMiddleware for EndpointMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let extensions = &request.extensions; - let endpoint_provider: &Box = extensions.get().unwrap(); + let endpoint_provider: &Arc = request.config.endpoint_provider().ok_or_else(||"missing endpoint provider")?; endpoint_provider.set_endpoint(&mut request.base.uri_mut()); Ok(()) } diff --git a/aws/rust-runtime/operation/src/extensions.rs b/aws/rust-runtime/operation/src/extensions.rs index 6d398c27ab..41693876cb 100644 --- a/aws/rust-runtime/operation/src/extensions.rs +++ b/aws/rust-runtime/operation/src/extensions.rs @@ -44,6 +44,16 @@ pub struct Extensions { map: Option>, } +/* +macro_rules! extension_trait { + ($name1:expr, $name2:expr, $t:ty) => {{ + trait $name1 { + + } + + }} +}*/ + impl Extensions { /// Create an empty `Extensions`. #[inline] diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 00655b1c5b..9a6846f5e2 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -3,17 +3,17 @@ use bytes::Bytes; use auth::{ProvideCredentials, SigningConfig}; pub mod endpoint; +mod extensions; pub mod middleware; pub mod signing_middleware; -mod extensions; +use crate::extensions::Extensions; use endpoint::ProvideEndpoint; use http::{HeaderMap, HeaderValue, Response}; use std::error::Error; use std::pin::Pin; -use std::task::{Context, Poll}; use std::sync::{Arc, Mutex}; -use crate::extensions::Extensions; +use std::task::{Context, Poll}; type BodyError = Box; @@ -81,8 +81,7 @@ pub struct Operation { pub struct Request { pub base: http::Request, - pub extensions: Extensions, - + pub config: Extensions, // These could also be attached in as extensions, but explicit might be better. // Having some explicit configurations as explicit fields doesn't preclude storing data as // extensions in the future @@ -92,33 +91,12 @@ pub struct Request { } impl Request { - pub fn new(base: http::Request) -> Self { Request { base, - extensions: Extensions::new() + config: Extensions::new(), } } - - pub fn signing_config(&self) -> &SigningConfig { - self.extensions.get().unwrap() - } - - pub fn credentials_provider(&self) -> &Box { - self.extensions.get().unwrap() - } - - pub fn endpoint_provider(&self) -> &Box { - self.extensions.get().unwrap() - } - - pub fn request_mut(&mut self) -> &mut http::Request { - &mut self.base - } - - pub fn add_config(&mut self, val: T) -> Option { - self.extensions.insert(val) - } } pub trait ParseHttpResponse { diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 9f5f402389..4307ca42ce 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -234,27 +234,29 @@ mod test { } }); let mut service = add_header.layer(DispatchLayer.layer(http_service)); - let operation = crate::Request::new(Request::builder() + let operation = crate::Request::new( + Request::builder() .uri("/some_url") .body(SdkBody::from("Hello")) - .unwrap()); /*, - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - service: "svc".to_string(), - region: "region".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), - }, - double_uri_encode: false, - normalize_uri_path: false, - omit_session_token: false, - }), - credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), - endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - };*/ + .unwrap(), + ); /*, + signing_config: SigningConfig::Http(HttpSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service_config: ServiceConfig { + service: "svc".to_string(), + region: "region".to_string(), + }, + request_config: RequestConfig { + request_ts: || SystemTime::now(), + }, + double_uri_encode: false, + normalize_uri_path: false, + omit_session_token: false, + }), + credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), + endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), + };*/ let response = service.call(operation).await; assert_eq!(response.unwrap().body(), "x-key:\"X-Key\""); } diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 7d1298914e..889224ccfb 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -2,10 +2,12 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ +use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; use crate::SdkBody; -use auth::{HttpSigner, SigningConfig, ProvideCredentials}; +use auth::{HttpSigner, ProvideCredentials, SigningConfig}; use std::error::Error; +use std::sync::Arc; #[derive(Clone)] pub struct SigningMiddleware { @@ -26,10 +28,52 @@ impl SigningMiddleware { } } +pub trait SigningConfigExt { + fn signing_config(&self) -> Option<&SigningConfig>; + fn insert_signing_config(&mut self, signing_config: SigningConfig) -> Option; +} + +impl SigningConfigExt for Extensions { + fn signing_config(&self) -> Option<&SigningConfig> { + self.get() + } + + fn insert_signing_config(&mut self, signing_config: SigningConfig) -> Option { + self.insert(signing_config) + } +} + +pub trait CredentialProviderExt { + fn credentials_provider(&self) -> Option<&Arc>; + fn insert_credentials_provider( + &mut self, + provider: Arc, + ) -> Option>; +} + +impl CredentialProviderExt for Extensions { + fn credentials_provider(&self) -> Option<&Arc> { + self.get() + } + + fn insert_credentials_provider( + &mut self, + provider: Arc, + ) -> Option> { + self.insert(provider) + } +} + impl OperationMiddleware for SigningMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let signing_config = request.extensions.get::().unwrap(); - let cred_provider: &Box = request.extensions.get().unwrap(); + let signing_config = request + .config + .signing_config() + .ok_or_else(||"Missing signing config")?; + let cred_provider = request + .config + .credentials_provider() + .ok_or_else (||"Missing credentials provider")?; let creds = cred_provider.credentials()?; let body = match request.base.body() { SdkBody::Once(Some(bytes)) => bytes.clone(), diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt index 87aac4975d..d8474a21a4 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt @@ -21,22 +21,22 @@ import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfi class CredentialProviderConfig : ConfigCustomization() { override fun section(section: ServiceConfig) = writable { when (section) { - is ServiceConfig.ConfigStruct -> rust("pub credentials_provider: Box,", CredentialsProvider) + is ServiceConfig.ConfigStruct -> rust("pub credentials_provider: ::std::sync::Arc,", CredentialsProvider) is ServiceConfig.ConfigImpl -> emptySection is ServiceConfig.BuilderStruct -> - rust("credentials_provider: Option>", CredentialsProvider) + rust("credentials_provider: Option<::std::sync::Arc>", CredentialsProvider) ServiceConfig.BuilderImpl -> rust( """ pub fn credentials_provider(mut self, credentials_provider: impl #T + 'static) -> Self { - self.credentials_provider = Some(Box::new(credentials_provider)); + self.credentials_provider = Some(::std::sync::Arc::new(credentials_provider)); self } """, CredentialsProvider ) ServiceConfig.BuilderBuild -> rust( - "credentials_provider: self.credentials_provider.unwrap_or_else(|| Box::new(#T())),", + "credentials_provider: self.credentials_provider.unwrap_or_else(|| ::std::sync::Arc::new(#T())),", DefaultProvider ) } diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index 4b13e0d1e5..4c2c4f96e0 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -31,20 +31,25 @@ impl ParseStrictResponse for DeleteTable { } use auth::SigningConfig; +use operation::endpoint::{StaticEndpoint, ProvideEndpoint, EndpointProviderExt}; +use std::sync::Arc; +use operation::signing_middleware::{SigningConfigExt, CredentialProviderExt}; impl DeleteTable { - fn into_operation(self, config: dynamodb::Config) -> Operation { + fn into_operation(self, config: &dynamodb::Config) -> Operation { let mut request = operation::Request::new(self.0.build_http_request().map(|body|SdkBody::from(body))); - request.extensions.insert(SigningConfig::default_configuration( - RequestConfig { - request_ts: ||SystemTime::now() - }, + request.config.insert_signing_config(SigningConfig::default_config( ServiceConfig { service: "dynamodb".into(), region: "us-east-1".into() - } + }, + RequestConfig { + request_ts: ||SystemTime::now() + }, )); - request.extensions.insert(config.credentials_provider); + request.config.insert_credentials_provider(config.credentials_provider.clone()); + let endpoint_config: Arc = Arc::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))); + request.config.insert_endpoint_provider(endpoint_config); Operation { request, response_handler: Box::new(self) @@ -56,87 +61,16 @@ impl DeleteTable { #[tokio::main] async fn main() -> Result<(), Box> { let table_name = "new_table"; - //let client = aws_hyper::Client::default(); - let client = io_v0::Client::local("dynamodb"); let config = dynamodb::Config::builder().build(); - let clear_table = dynamodb::operation::DeleteTable::builder() - .table_name(table_name) - .build(&config); - - - match io_v0::dispatch!(client, clear_table).parsed() { - Ok(Ok(table_deleted)) => println!( - "{:?} was deleted", - table_deleted - .table_description - .as_ref() - .unwrap() - .table_name - .as_ref() - .unwrap() - ), - Ok(Err(table_del_error)) => println!("failed to delete table: {}", table_del_error), - Err(e) => println!("dispatch error: {:?}", e), - } - - let tables = io_v0::dispatch!( - client, - dynamodb::operation::ListTables::builder().build(&config) - ) - .parsed - .unwrap(); - assert_eq!( - tables.unwrap(), - ListTablesOutput::builder().table_names(vec![]).build() - ); - println!("no tables...creating table"); - - let create_table = CreateTable::builder() + let client = aws_hyper::Client::default(); + let delete_table = dynamodb::operation::DeleteTable::builder() .table_name(table_name) - .attribute_definitions(vec![AttributeDefinition::builder() - .attribute_name("ForumName") - .attribute_type(ScalarAttributeType::S) - .build()]) - .key_schema(vec![KeySchemaElement::builder() - .attribute_name("ForumName") - .key_type(KeyType::Hash) - .build()]) - .provisioned_throughput( - ProvisionedThroughput::builder() - .read_capacity_units(100) - .write_capacity_units(100) - .build(), - ) .build(&config); - - let response = io_v0::dispatch!(client, create_table); - match response.parsed { - Some(Ok(output)) => { - assert_eq!( - output.table_description.unwrap().table_name.unwrap(), - table_name - ); - println!("{} was created", table_name); - } - _ => println!("{:?}", response.raw), + let clear_table = DeleteTable(delete_table).into_operation(&config); + let response = client.call(clear_table).await; + match response { + Ok(output) => println!("deleted! {:?}", output.parsed), + Err(e) => println!("err: {:?}", e.error()) } - - let tables = io_v0::dispatch!( - client, - dynamodb::operation::ListTables::builder().build(&config) - ) - .parsed - .unwrap(); - println!( - "current tables: {:?}", - &tables.as_ref().unwrap().table_names - ); - assert_eq!( - tables.unwrap(), - ListTablesOutput::builder() - .table_names(vec![table_name.to_string()]) - .build() - ); - Ok(()) } From a0fedb93b25f8291fad81caf52c0ebfc7ad57cef Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Sat, 16 Jan 2021 21:28:15 -0500 Subject: [PATCH 10/50] Working Dynamo IT again! --- .../smithy/rustsdk/AwsCodegenDecorator.kt | 20 ++++- .../rustsdk/CredentialProviderConfig.kt | 2 +- .../amazon/smithy/rustsdk/EndpointConfig.kt | 75 +++++++++++++++++++ .../amazon/smithy/rustsdk/RegionConfig.kt | 39 ++++++++++ .../amazon/smithy/rustsdk/SigningConfig.kt | 61 +++++++++++++++ aws/sdk/dynamo-it/Cargo.lock | 2 + aws/sdk/dynamo-it/src/main.rs | 67 ++++------------- .../rust/codegen/rustlang/CargoDependency.kt | 2 + .../rust/codegen/smithy/RuntimeTypes.kt | 6 ++ .../smithy/generators/BuilderGenerator.kt | 35 +++++++-- .../generators/HttpProtocolGenerator.kt | 6 +- .../config/ServiceConfigGenerator.kt | 7 +- .../codegen/smithy/protocols/AwsJson10.kt | 16 ++++ 13 files changed, 274 insertions(+), 64 deletions(-) create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt 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 e0ca6bf267..63e70f74af 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 @@ -5,7 +5,10 @@ package software.amazon.smithy.rustsdk +import software.amazon.smithy.aws.traits.auth.SigV4Trait +import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.smithy.RustCodegenDecorator +import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization @@ -16,6 +19,21 @@ class AwsCodegenDecorator : RustCodegenDecorator { protocolConfig: ProtocolConfig, baseCustomizations: List ): List { - return listOf(CredentialProviderConfig()) + baseCustomizations + val awsCustomizations = mutableListOf() + awsCustomizations += CredentialProviderConfig() + awsCustomizations += RegionConfig() + awsCustomizations += EndpointConfigCustomization(protocolConfig) + protocolConfig.serviceShape.getTrait(SigV4Trait::class.java).map { trait -> + awsCustomizations += SigV4SigningConfig(trait) + } + return awsCustomizations + baseCustomizations + } + + override fun operationCustomizations( + protocolConfig: ProtocolConfig, + operation: OperationShape, + baseCustomizations: List + ): List { + return listOf(SigV4SigningPlugin(operation), EndpointConfigPlugin(operation)) + baseCustomizations } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt index d8474a21a4..86e5c2caf9 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt @@ -24,7 +24,7 @@ class CredentialProviderConfig : ConfigCustomization() { is ServiceConfig.ConfigStruct -> rust("pub credentials_provider: ::std::sync::Arc,", CredentialsProvider) is ServiceConfig.ConfigImpl -> emptySection is ServiceConfig.BuilderStruct -> - rust("credentials_provider: Option<::std::sync::Arc>", CredentialsProvider) + rust("credentials_provider: Option<::std::sync::Arc>,", CredentialsProvider) ServiceConfig.BuilderImpl -> rust( """ diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt new file mode 100644 index 0000000000..6e02a5ce4f --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt @@ -0,0 +1,75 @@ +/* + * 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.ServiceTrait +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.traits.EndpointTrait +import software.amazon.smithy.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig +import software.amazon.smithy.rust.codegen.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.OperationSection +import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig +import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig +import software.amazon.smithy.rust.codegen.util.dq + +class EndpointConfigCustomization(private val protocolConfig: ProtocolConfig) : ConfigCustomization() { + private val endpointProvider = EndpointProvider(protocolConfig.runtimeConfig) + private val endpointPrefix = protocolConfig.serviceShape.expectTrait(ServiceTrait::class.java).endpointPrefix + override fun section(section: ServiceConfig): Writable = writable { + when (section) { + is ServiceConfig.ConfigStruct -> rust("pub endpoint_provider: ::std::sync::Arc,", endpointProvider) + is ServiceConfig.ConfigImpl -> emptySection + is ServiceConfig.BuilderStruct -> + rust("endpoint_provider: Option<::std::sync::Arc>,", endpointProvider) + ServiceConfig.BuilderImpl -> + rust( + """ + pub fn endpoint_provider(mut self, endpoint_provider: impl #T + 'static) -> Self { + self.endpoint_provider = Some(::std::sync::Arc::new(endpoint_provider)); + self + } + """, + endpointProvider + ) + ServiceConfig.BuilderBuild -> rust( + """endpoint_provider: self.endpoint_provider.unwrap_or_else(|| + ::std::sync::Arc::new( + #T::from_service_region(${endpointPrefix.dq()}, ®ion) + ) + ),""", + StaticEndpoint(protocolConfig.runtimeConfig) + ) + } + } +} + +fun EndpointProvider(runtimeConfig: RuntimeConfig) = RuntimeType("ProvideEndpoint", CargoDependency.Operation(runtimeConfig), "operation::endpoint") +fun StaticEndpoint(runtimeConfig: RuntimeConfig) = RuntimeType("StaticEndpoint", CargoDependency.Operation(runtimeConfig), "operation::endpoint") + +class EndpointConfigPlugin(private val operationShape: OperationShape) : OperationCustomization() { + override fun section(section: OperationSection): Writable { + if (operationShape.hasTrait(EndpointTrait::class.java)) { + TODO() + } + return when (section) { + OperationSection.ImplBlock -> emptySection + OperationSection.Plugin -> writable { + rust( + """ + use operation::endpoint::EndpointProviderExt; + request.config.insert_endpoint_provider(_config.endpoint_provider.clone()); + """ + ) + } + } + } +} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt new file mode 100644 index 0000000000..2979f49a04 --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt @@ -0,0 +1,39 @@ +/* + * 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.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig + +class RegionConfig : ConfigCustomization() { + override fun section(section: ServiceConfig) = writable { + when (section) { + is ServiceConfig.ConfigStruct -> rust("pub region: String,") + is ServiceConfig.ConfigImpl -> emptySection + is ServiceConfig.BuilderStruct -> + rust("region: Option,") + ServiceConfig.BuilderImpl -> + rust( + """ + pub fn region(mut self, region: impl ToString) -> Self { + self.region = Some(region.to_string()); + self + } + """, + ) + ServiceConfig.BuilderPreamble -> rust( + // TODO: design a config that enables resolving the default region chain + // clone because the region is also used + """let region = self.region.unwrap_or_else(|| "us-east-1".to_string());""", + ) + ServiceConfig.BuilderBuild -> rust( + """region: region.clone(),""", + ) + } + } +} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt new file mode 100644 index 0000000000..38a3e2b4ed --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt @@ -0,0 +1,61 @@ +/* + * 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.model.shapes.OperationShape +import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.OperationSection +import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig +import software.amazon.smithy.rust.codegen.util.dq + +class SigV4SigningConfig(private val sigV4Trait: SigV4Trait) : ConfigCustomization() { + override fun section(section: ServiceConfig): Writable { + return when (section) { + is ServiceConfig.ConfigImpl -> writable { + rust( + """ + /// The signature version 4 service signing name to use in the credential scope when signing requests. + pub fn signing_service(&self) -> &'static str { + ${sigV4Trait.name.dq()} + } + """ + ) + } + else -> emptySection + } + } +} + +class SigV4SigningPlugin(operationShape: OperationShape) : OperationCustomization() { + override fun section(section: OperationSection): Writable { + return when (section) { + is OperationSection.Plugin -> writable { + rust( + """ + use operation::signing_middleware::SigningConfigExt; + request.config.insert_signing_config(auth::SigningConfig::default_config( + auth::ServiceConfig { + service: _config.signing_service().into(), + region: _config.region.clone().into() + }, + auth::RequestConfig { + request_ts: ||std::time::SystemTime::now() + }, + )); + use operation::signing_middleware::CredentialProviderExt; + request.config.insert_credentials_provider(_config.credentials_provider.clone()); + """ + ) + } + else -> emptySection + } + } +} diff --git a/aws/sdk/dynamo-it/Cargo.lock b/aws/sdk/dynamo-it/Cargo.lock index 8e4e3fea85..845e5c5330 100644 --- a/aws/sdk/dynamo-it/Cargo.lock +++ b/aws/sdk/dynamo-it/Cargo.lock @@ -163,7 +163,9 @@ name = "dynamodb" version = "0.0.1" dependencies = [ "auth", + "bytes 1.0.0", "http", + "operation", "rand 0.7.3", "serde", "serde_json", diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index 4c2c4f96e0..2116566a49 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -5,72 +5,33 @@ use std::error::Error; -use dynamodb::output::{DeleteTableOutput, ListTablesOutput}; -use operation::{SdkBody, Operation, ParseStrictResponse, Request}; use dynamodb::error::DeleteTableError; +use dynamodb::output::{DeleteTableOutput, ListTablesOutput}; -struct DeleteTable(dynamodb::operation::DeleteTable); - -//use bytes::Bytes; -//use auth::{SigningConfig, ServiceConfig, RequestConfig}; -//use std::time::SystemTime; -//use operation::endpoint::StaticEndpoint; -use http::{Response, Uri}; +use dynamodb::model::{ + AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, +}; use dynamodb::operation::CreateTable; -use dynamodb::model::{AttributeDefinition, ScalarAttributeType, KeySchemaElement, ProvisionedThroughput, KeyType}; -use bytes::Bytes; -use auth::{RequestConfig, ServiceConfig}; -use std::time::SystemTime; - - -impl ParseStrictResponse for DeleteTable { - type Output = Result; - fn parse(&self, response: &Response) -> Self::Output { - self.0.parse_response(response) - } -} - -use auth::SigningConfig; -use operation::endpoint::{StaticEndpoint, ProvideEndpoint, EndpointProviderExt}; -use std::sync::Arc; -use operation::signing_middleware::{SigningConfigExt, CredentialProviderExt}; - -impl DeleteTable { - fn into_operation(self, config: &dynamodb::Config) -> Operation { - let mut request = operation::Request::new(self.0.build_http_request().map(|body|SdkBody::from(body))); - request.config.insert_signing_config(SigningConfig::default_config( - ServiceConfig { - service: "dynamodb".into(), - region: "us-east-1".into() - }, - RequestConfig { - request_ts: ||SystemTime::now() - }, - )); - request.config.insert_credentials_provider(config.credentials_provider.clone()); - let endpoint_config: Arc = Arc::new(StaticEndpoint::from_uri(Uri::from_static("http://localhost:8000"))); - request.config.insert_endpoint_provider(endpoint_config); - Operation { - request, - response_handler: Box::new(self) - } - } -} - +use http::Uri; +use operation::endpoint::StaticEndpoint; #[tokio::main] async fn main() -> Result<(), Box> { let table_name = "new_table"; - let config = dynamodb::Config::builder().build(); + let config = dynamodb::Config::builder() + .region("us-east-1") + .endpoint_provider(StaticEndpoint::from_uri(Uri::from_static( + "http://localhost:8000", + ))) + .build(); let client = aws_hyper::Client::default(); let delete_table = dynamodb::operation::DeleteTable::builder() .table_name(table_name) .build(&config); - let clear_table = DeleteTable(delete_table).into_operation(&config); - let response = client.call(clear_table).await; + let response = client.call(delete_table).await; match response { Ok(output) => println!("deleted! {:?}", output.parsed), - Err(e) => println!("err: {:?}", e.error()) + Err(e) => println!("err: {:?}", e.error()), } Ok(()) } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt index 4d1171b526..8cb97d3fd6 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt @@ -149,8 +149,10 @@ data class CargoDependency( } companion object { + val Bytes: RustDependency = CargoDependency("bytes", CratesIo("1")) val Rand: CargoDependency = CargoDependency("rand", CratesIo("0.7")) val Http: CargoDependency = CargoDependency("http", CratesIo("0.2")) + fun Operation(runtimeConfig: RuntimeConfig): CargoDependency = CargoDependency("operation", Local(runtimeConfig.relativePath)) fun SmithyTypes(runtimeConfig: RuntimeConfig) = CargoDependency("${runtimeConfig.cratePrefix}-types", Local(runtimeConfig.relativePath)) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt index eedca4c115..fff0fb68cc 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt @@ -53,6 +53,8 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n // TODO: refactor to be RuntimeTypeProvider a la Symbol provider that packages the `RuntimeConfig` state. companion object { + val Bytes = RuntimeType("Bytes", dependency = CargoDependency.Bytes, namespace = "bytes") + // val Blob = RuntimeType("Blob", RustDependency.IO_CORE, "blob") val From = RuntimeType("From", dependency = null, namespace = "std::convert") val AsRef = RuntimeType("AsRef", dependency = null, namespace = "std::convert") @@ -141,6 +143,8 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n val Config = RuntimeType("config", null, "crate") + fun Operation(runtimeConfig: RuntimeConfig) = RuntimeType("Operation", dependency = CargoDependency.Operation(runtimeConfig), namespace = "operation") + fun BlobSerde(runtimeConfig: RuntimeConfig) = RuntimeType("blob_serde", InlineDependency.blobSerde(runtimeConfig), "crate") fun forInlineFun(name: String, module: String, func: (RustWriter) -> Unit) = RuntimeType( @@ -148,5 +152,7 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n dependency = InlineDependency(name, module, listOf(), func), namespace = "crate::$module" ) + + fun ParseStrict(runtimeConfig: RuntimeConfig): RuntimeType = RuntimeType("ParseStrictResponse", dependency = CargoDependency.Operation(runtimeConfig), namespace = "operation") } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index b9b56d7970..90b1429fc5 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.rustlang.conditionalBlock import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.render +import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustBlock import software.amazon.smithy.rust.codegen.rustlang.stripOuter import software.amazon.smithy.rust.codegen.rustlang.withBlock @@ -60,23 +61,43 @@ class ModelBuilderGenerator( class OperationInputBuilderGenerator( model: Model, private val symbolProvider: RustSymbolProvider, - private val shape: OperationShape + private val shape: OperationShape, + private val plugins: List = listOf() ) : BuilderGenerator(model, symbolProvider, shape.inputShape(model)) { override fun buildFn(implBlockWriter: RustWriter) { val fallibleBuilder = StructureGenerator.fallibleBuilder(shape.inputShape(model), symbolProvider) val returnType = when (fallibleBuilder) { - true -> "Result<#T, String>" - false -> "#T" + true -> "Result<#T<#{T}>, String>" + false -> "#T<#T>" } val outputSymbol = symbolProvider.toSymbol(shape) - implBlockWriter.docs("Consumes the builder and constructs a #D", outputSymbol) - implBlockWriter.rustBlock("pub fn build(self, _config: &#T::Config) -> $returnType", RuntimeType.Config, outputSymbol) { + implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) + implBlockWriter.rustBlock("pub fn build(self, _config: &#T::Config) -> $returnType", RuntimeType.Config, RuntimeType.Operation(symbolProvider.config().runtimeConfig), outputSymbol) { conditionalBlock("Ok(", ")", conditional = fallibleBuilder) { - // If a wrapper is specified, use the `::new` associated function to construct the wrapper - withBlock("#T::new(", ")", outputSymbol) { + withBlock("let op = #T::new(", ");", outputSymbol) { coreBuilder(this) } + val mut = if (plugins.isEmpty()) { + "" + } else { + "mut" + } + rust( + """ + let $mut request = operation::Request::new(op.build_http_request().map(|body|operation::SdkBody::from(body))); + """ + ) + plugins.forEach { it.section(OperationSection.Plugin)(this) } + rust( + """ + #T { + request, + response_handler: Box::new(op) + } + """, + RuntimeType.Operation(symbolProvider.config().runtimeConfig) + ) } } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt index 77ecd92370..74be1743e4 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt @@ -42,6 +42,7 @@ interface ProtocolGeneratorFactory { sealed class OperationSection(name: String) : Section(name) { object ImplBlock : OperationSection("ImplBlock") + object Plugin : OperationSection("Feature") } typealias OperationCustomization = NamedSectionGenerator @@ -63,7 +64,7 @@ abstract class HttpProtocolGenerator( ) { val inputShape = operationShape.inputShape(model) val inputSymbol = symbolProvider.toSymbol(inputShape) - val builderGenerator = OperationInputBuilderGenerator(model, symbolProvider, operationShape) + val builderGenerator = OperationInputBuilderGenerator(model, symbolProvider, operationShape, customizations) builderGenerator.render(inputWriter) // impl OperationInputShape { ... } inputWriter.implBlock(inputShape, symbolProvider) { @@ -85,6 +86,7 @@ abstract class HttpProtocolGenerator( // pub fn builder() -> ... { } builderGenerator.renderConvenienceMethod(this) } + extras(operationWriter, operationShape) val operationName = symbolProvider.toSymbol(operationShape).name operationWriter.documentShape(operationShape, model) operationWriter.rustBlock("pub struct $operationName") { @@ -169,4 +171,6 @@ abstract class HttpProtocolGenerator( operationShape: OperationShape, inputShape: StructureShape ) + + open fun extras(moduleWriter: RustWriter, operationShape: OperationShape) {} } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGenerator.kt index b47cbe46ac..453ee0af7f 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGenerator.kt @@ -54,13 +54,17 @@ sealed class ServiceConfig(name: String) : Section(name) { object BuilderStruct : ServiceConfig("BuilderStruct") /** impl block of `ConfigBuilder` **/ object BuilderImpl : ServiceConfig("BuilderImpl") + + /** Setup shared resources in the build method **/ + object BuilderPreamble : ServiceConfig("BuilderBuildPreamble") + /** Convert from a field in the builder to the final field in config * eg. * ```kotlin * rust("""my_field: my_field.unwrap_or_else(||"default")""") * ``` **/ - object BuilderBuild : ServiceConfig("BuilderBuild") + object BuilderBuild : ServiceConfig("BuilderBuildPreamble") } // TODO: if this becomes hot, it may need to be cached in a knowledge index @@ -130,6 +134,7 @@ class ServiceConfigGenerator(private val customizations: List Config") { + customizations.forEach { it.section(ServiceConfig.BuilderPreamble)(this) } rustBlock("Config") { customizations.forEach { it.section(ServiceConfig.BuilderBuild)(this) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt index 0d1695bdd0..c6172fdf4d 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt @@ -37,6 +37,7 @@ import software.amazon.smithy.rust.codegen.smithy.traits.SyntheticOutputTrait import software.amazon.smithy.rust.codegen.smithy.transformers.OperationNormalizer import software.amazon.smithy.rust.codegen.smithy.transformers.StructureModifier import software.amazon.smithy.rust.codegen.util.dq +import software.amazon.smithy.rust.codegen.util.outputShape sealed class AwsJsonVersion { abstract val value: String @@ -262,4 +263,19 @@ class BasicAwsJsonGenerator( } write("unknown => #T::unhandled(unknown)", errorSymbol) } + + override fun extras(moduleWriter: RustWriter, operationShape: OperationShape) { + val outputSymbol = symbolProvider.toSymbol(operationShape.outputShape(model)) + moduleWriter.rustTemplate( + """ + impl #{parse_strict} for ${symbolProvider.toSymbol(operationShape).name} { + type Output = Result<#{output}, #{error}>; + fn parse(&self, response: &#{response}<#{bytes}>) -> Self::Output { + self.parse_response(response) + } + } + """, + "parse_strict" to RuntimeType.ParseStrict(symbolProvider.config().runtimeConfig), "output" to outputSymbol, "error" to operationShape.errorSymbol(symbolProvider), "response" to RuntimeType.Http("Response"), "bytes" to RuntimeType.Bytes + ) + } } From 39e61d75682a002a798b4a11e8cc7af73fdbcffd Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Sun, 17 Jan 2021 10:23:13 -0500 Subject: [PATCH 11/50] more clippy cleanup --- aws/rust-runtime/auth/src/lib.rs | 2 +- aws/rust-runtime/aws-hyper/src/lib.rs | 54 +++++++++++++++---- aws/rust-runtime/operation/src/endpoint.rs | 8 +-- aws/rust-runtime/operation/src/lib.rs | 4 -- aws/rust-runtime/operation/src/middleware.rs | 8 +-- .../operation/src/signing_middleware.rs | 4 +- aws/sdk/dynamo-it/src/main.rs | 45 +++++++++++----- 7 files changed, 85 insertions(+), 40 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 407fe82039..b81949c703 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::error::Error; use std::fmt::{Display, Formatter}; -use std::time::{Instant, SystemTime}; +use std::time::SystemTime; /// AWS SDK Credentials /// diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 752aed6b52..2a55d66ac6 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -13,6 +13,7 @@ pub struct SdkResponse { pub parsed: O, } +#[derive(Debug)] pub enum SdkError { DispatchFailure(Box), ResponseError { @@ -137,19 +138,16 @@ async fn read_body(body: B) -> Result, B::Error> { #[cfg(test)] mod test { use crate::{read_body, Client}; - use auth::{ - Credentials, HttpSignatureType, HttpSigningConfig, RequestConfig, ServiceConfig, - SigningAlgorithm, SigningConfig, - }; + use auth::Credentials; use bytes::Bytes; - use http::{Request, Response}; + use http::{Request, Response, Uri}; use hyper::service::service_fn; use operation::endpoint::StaticEndpoint; + use operation::signing_middleware::SigningConfigExt; use operation::{Operation, ParseHttpResponse, SdkBody}; use pin_utils::core_reexport::fmt::Formatter; use std::error::Error; use std::sync::{Arc, Mutex}; - use std::time::SystemTime; #[derive(Clone)] struct TestOperationParser; @@ -180,7 +178,41 @@ mod test { } impl Error for TestError {}; + let mut request = operation::Request::new( + Request::builder() + .uri("/some_url") + .body(SdkBody::from("Hello")) + .unwrap(), + ); + + request + .config + .insert_signing_config(auth::SigningConfig::default_config( + auth::ServiceConfig { + service: "some-service".into(), + region: "some-region".into(), + }, + auth::RequestConfig { + request_ts: || std::time::SystemTime::now(), + }, + )); + use operation::signing_middleware::CredentialProviderExt; + request + .config + .insert_credentials_provider(Arc::new(Credentials::from_static("access", "secret"))); + + use operation::endpoint::EndpointProviderExt; + request + .config + .insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + "http://localhost:8000", + )))); let operation = Operation { + request, + response_handler: Box::new(TestOperationParser), + }; + + /*let operation = Operation { request: operation::Request { base: Request::builder() .uri("/some_url") @@ -207,7 +239,7 @@ mod test { )), }, response_handler: Box::new(TestOperationParser), - }; + };*/ let test_request: Arc>>> = Arc::new(Mutex::new(None)); let http_service = service_fn(|request: Request| async { @@ -218,12 +250,13 @@ mod test { "hello!", ))) }); - //let x: () = http_service; - //http_service.call(http::Request::new(SdkBody::from("123"))); let client = Client { inner: http_service, }; - let response = client.call(operation).await; + let _ = client + .call(operation) + .await + .expect("operation should succeed"); let request = test_request.lock().unwrap().take().unwrap(); assert_eq!( request @@ -233,7 +266,6 @@ mod test { .collect::>(), vec!["authorization", "x-amz-date"] ); - assert!(response.is_ok()); } /* diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index 1de1fde227..bc7441ed3d 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -9,9 +9,9 @@ use std::str::FromStr; use http::uri::Uri; +use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; use std::sync::Arc; -use crate::extensions::Extensions; pub struct StaticEndpoint(http::Uri); @@ -67,7 +67,6 @@ where } } - pub trait EndpointProviderExt { fn endpoint_provider(&self) -> Option<&Arc>; fn insert_endpoint_provider( @@ -95,7 +94,10 @@ impl EndpointProviderExt for Extensions { pub struct EndpointMiddleware; impl OperationMiddleware for EndpointMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let endpoint_provider: &Arc = request.config.endpoint_provider().ok_or_else(||"missing endpoint provider")?; + let endpoint_provider: &Arc = request + .config + .endpoint_provider() + .ok_or("missing endpoint provider")?; endpoint_provider.set_endpoint(&mut request.base.uri_mut()); Ok(()) } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 9a6846f5e2..68391538a7 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -1,18 +1,14 @@ use bytes::Bytes; -use auth::{ProvideCredentials, SigningConfig}; - pub mod endpoint; mod extensions; pub mod middleware; pub mod signing_middleware; use crate::extensions::Extensions; -use endpoint::ProvideEndpoint; use http::{HeaderMap, HeaderValue, Response}; use std::error::Error; use std::pin::Pin; -use std::sync::{Arc, Mutex}; use std::task::{Context, Poll}; type BodyError = Box; diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 4307ca42ce..bb5687f5af 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -169,19 +169,15 @@ where #[cfg(test)] mod test { - use crate::endpoint::StaticEndpoint; use crate::middleware::{DispatchLayer, OperationMiddleware, OperationRequestMiddlewareLayer}; use crate::{ParseHttpResponse, SdkBody}; - use auth::{ - Credentials, HttpSignatureType, HttpSigningConfig, RequestConfig, ServiceConfig, - SigningAlgorithm, SigningConfig, - }; + use bytes::Bytes; use http::header::HeaderName; use http::{HeaderValue, Request, Response}; use std::error::Error; use std::str::FromStr; - use std::time::SystemTime; + use tower::service_fn; use tower::{Layer, Service}; diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 889224ccfb..702255970a 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -69,11 +69,11 @@ impl OperationMiddleware for SigningMiddleware { let signing_config = request .config .signing_config() - .ok_or_else(||"Missing signing config")?; + .ok_or("Missing signing config")?; let cred_provider = request .config .credentials_provider() - .ok_or_else (||"Missing credentials provider")?; + .ok_or("Missing credentials provider")?; let creds = cred_provider.credentials()?; let body = match request.base.body() { SdkBody::Once(Some(bytes)) => bytes.clone(), diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index 2116566a49..eccf49acbe 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -5,19 +5,15 @@ use std::error::Error; -use dynamodb::error::DeleteTableError; -use dynamodb::output::{DeleteTableOutput, ListTablesOutput}; -use dynamodb::model::{ - AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, -}; -use dynamodb::operation::CreateTable; + + +use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; use http::Uri; use operation::endpoint::StaticEndpoint; #[tokio::main] async fn main() -> Result<(), Box> { - let table_name = "new_table"; let config = dynamodb::Config::builder() .region("us-east-1") .endpoint_provider(StaticEndpoint::from_uri(Uri::from_static( @@ -25,13 +21,36 @@ async fn main() -> Result<(), Box> { ))) .build(); let client = aws_hyper::Client::default(); - let delete_table = dynamodb::operation::DeleteTable::builder() - .table_name(table_name) + let list_tables = dynamodb::operation::ListTables::builder().build(&config); + + let response = client.call(list_tables).await; + let tables = match response { + Ok(output) => { + output.parsed.table_names.unwrap() + }, + Err(e) => panic!("err: {:?}", e.error()), + }; + if tables.is_empty() { + let create_table = CreateTable::builder() + .table_name("new_table") + .attribute_definitions(vec![AttributeDefinition::builder() + .attribute_name("ForumName") + .attribute_type(ScalarAttributeType::S) + .build()]) + .key_schema(vec![KeySchemaElement::builder() + .attribute_name("ForumName") + .key_type(KeyType::Hash) + .build()]) + .provisioned_throughput( + ProvisionedThroughput::builder() + .read_capacity_units(100) + .write_capacity_units(100) + .build(), + ) .build(&config); - let response = client.call(delete_table).await; - match response { - Ok(output) => println!("deleted! {:?}", output.parsed), - Err(e) => println!("err: {:?}", e.error()), + client.call(create_table).await.map_err(|err| { + eprintln!("failed to create table: {}", err.error()); + }); } Ok(()) } From ba0adbce8f8e8a4aa4cf81101362e213188808e9 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Sun, 17 Jan 2021 10:31:29 -0500 Subject: [PATCH 12/50] Update IT --- aws/sdk/dynamo-it/src/main.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index eccf49acbe..d6ca0e5216 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -11,6 +11,9 @@ use std::error::Error; use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; use http::Uri; use operation::endpoint::StaticEndpoint; +use aws_hyper::{SdkError, SdkResponse}; +use dynamodb::output::CreateTableOutput; +use dynamodb::error::CreateTableError; #[tokio::main] async fn main() -> Result<(), Box> { @@ -48,9 +51,10 @@ async fn main() -> Result<(), Box> { .build(), ) .build(&config); - client.call(create_table).await.map_err(|err| { - eprintln!("failed to create table: {}", err.error()); - }); + match client.call(create_table).await { + Ok(created) => println!("table created! {:#?}", created.parsed), + Err(failed) => println!("failed to create table: {:?}", failed) + } } Ok(()) } From 82cf56478a61e4e63673d7b5a329b9fcc54fc2da Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Sun, 17 Jan 2021 10:32:16 -0500 Subject: [PATCH 13/50] Fixup imports --- aws/sdk/dynamo-it/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/dynamo-it/src/main.rs index d6ca0e5216..720ec2a39d 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/dynamo-it/src/main.rs @@ -11,9 +11,9 @@ use std::error::Error; use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; use http::Uri; use operation::endpoint::StaticEndpoint; -use aws_hyper::{SdkError, SdkResponse}; -use dynamodb::output::CreateTableOutput; -use dynamodb::error::CreateTableError; + + + #[tokio::main] async fn main() -> Result<(), Box> { From bded4d5dc10ac4c8d2c3f79ce0a3668e6b572105 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Sun, 17 Jan 2021 10:33:08 -0500 Subject: [PATCH 14/50] Include the Dynamo IT in tests --- aws/sdk/build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index c24562648a..988153f91a 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -188,10 +188,9 @@ tasks.register("dynamoIt") { // disallow warnings commandLine("cargo", "run") dependsOn("assemble") - } -tasks["test"].finalizedBy("cargoCheck", "cargoClippy", "cargoTest", "cargoDocs") +tasks["test"].finalizedBy("cargoCheck", "cargoClippy", "cargoTest", "cargoDocs", "dynamoIt") tasks["clean"].doFirst { delete("smithy-build.json") From 1523fa5c974f2badfa6435cf502952b3796e85d2 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 19 Jan 2021 10:23:40 -0500 Subject: [PATCH 15/50] Generate examples in build artifact --- aws/sdk/build.gradle.kts | 26 +- aws/sdk/dynamo-it/Cargo.toml | 23 - .../dynamo-helloworld}/.gitignore | 0 .../dynamo-helloworld}/Cargo.lock | 592 ++---------------- aws/sdk/examples/dynamo-helloworld/Cargo.toml | 14 + .../dynamo-helloworld}/docker-compose.yml | 0 .../dynamo-helloworld}/src/main.rs | 6 - .../config/ServiceConfigGeneratorTest.kt | 1 + 8 files changed, 88 insertions(+), 574 deletions(-) delete mode 100644 aws/sdk/dynamo-it/Cargo.toml rename aws/sdk/{dynamo-it => examples/dynamo-helloworld}/.gitignore (100%) rename aws/sdk/{dynamo-it => examples/dynamo-helloworld}/Cargo.lock (70%) create mode 100644 aws/sdk/examples/dynamo-helloworld/Cargo.toml rename aws/sdk/{dynamo-it => examples/dynamo-helloworld}/docker-compose.yml (100%) rename aws/sdk/{dynamo-it => examples/dynamo-helloworld}/src/main.rs (99%) diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index 988153f91a..86dc3640ec 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -21,7 +21,8 @@ val smithyVersion: String by project val sdkOutputDir = buildDir.resolve("aws-sdk") val awsServices = discoverServices() // TODO: smithy-http should be removed -val runtimeModules = listOf("smithy-types", "smithy-http", "io-v0") +val runtimeModules = listOf("smithy-types", "smithy-http") +val examples = listOf("dynamo-helloworld") val awsModules = listOf("auth", "operation", "aws-hyper") buildscript { @@ -104,6 +105,19 @@ task("relocateServices") { } } +task("relocateExamples") { + description = "relocate the examples folder & rewrite path dependencies" + doLast { + copy { + from(projectDir) + include("examples/**") + into(sdkOutputDir) + exclude("**/target") + filter { line -> line.replace("build/aws-sdk/", "") } + } + } +} + tasks.register("relocateRuntime") { from("$rootDir/rust-runtime") { runtimeModules.forEach { @@ -127,7 +141,7 @@ tasks.register("relocateAwsRuntime") { } fun generateCargoWorkspace(services: List): String { - val modules = services.map(AwsService::module) + runtimeModules + val modules = services.map(AwsService::module) + awsModules + runtimeModules + examples.map { "examples/$it" } return """ [workspace] members = [ @@ -143,7 +157,13 @@ task("generateCargoWorkspace") { } task("finalizeSdk") { - finalizedBy("relocateServices", "relocateRuntime", "relocateAwsRuntime", "generateCargoWorkspace") + finalizedBy( + "relocateServices", + "relocateRuntime", + "relocateAwsRuntime", + "generateCargoWorkspace", + "relocateExamples" + ) } tasks["smithyBuildJar"].dependsOn("generateSmithyBuild") diff --git a/aws/sdk/dynamo-it/Cargo.toml b/aws/sdk/dynamo-it/Cargo.toml deleted file mode 100644 index 43b07f24f1..0000000000 --- a/aws/sdk/dynamo-it/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "dynamo-it" -version = "0.1.0" -authors = ["Russell Cohen "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -smithy-types = { path = "../build/aws-sdk/smithy-types" } -dynamodb = { version = "0.0.1", path = "../build/aws-sdk/dynamodb"} -io-v0 = { path = "../build/aws-sdk/io-v0" } -aws-hyper = { path = "../build/aws-sdk/aws-hyper"} -tokio = { version = "1", features = ["full"] } -rand = "0.7.3" -bytes = "1" -hyper = "0.14.2" - - -# these are just for the stub implementation -operation = { path = "../build/aws-sdk/operation"} -auth = { path = "../build/aws-sdk/auth" } -http = "0.2.3" diff --git a/aws/sdk/dynamo-it/.gitignore b/aws/sdk/examples/dynamo-helloworld/.gitignore similarity index 100% rename from aws/sdk/dynamo-it/.gitignore rename to aws/sdk/examples/dynamo-helloworld/.gitignore diff --git a/aws/sdk/dynamo-it/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock similarity index 70% rename from aws/sdk/dynamo-it/Cargo.lock rename to aws/sdk/examples/dynamo-helloworld/Cargo.lock index 845e5c5330..b7f01ae2d5 100644 --- a/aws/sdk/dynamo-it/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -4,7 +4,7 @@ name = "auth" version = "0.1.0" dependencies = [ - "aws-sigv4 0.0.1 (git+https://github.com/rcoh/sigv4)", + "aws-sigv4", "http", ] @@ -19,34 +19,14 @@ name = "aws-hyper" version = "0.1.0" dependencies = [ "auth", - "bytes 1.0.0", + "bytes", "http", - "http-body 0.4.0", - "hyper 0.14.2", + "http-body", + "hyper", "hyper-tls", "operation", "pin-utils", - "tower 0.4.2", -] - -[[package]] -name = "aws-sigv4" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85293e31cbf209322718ff220c48470f5dd31f39f652220bba6f3ceb2579cc81" -dependencies = [ - "bytes 0.5.6", - "chrono", - "eliza_error", - "hex", - "http", - "http-body 0.3.1", - "httparse", - "hyper 0.13.9", - "ring", - "serde", - "serde_urlencoded 0.5.5", - "tower 0.3.1", + "tower", ] [[package]] @@ -54,14 +34,14 @@ name = "aws-sigv4" version = "0.0.1" source = "git+https://github.com/rcoh/sigv4#ef394a689c695f057ce9870b38bf4b470efcfc36" dependencies = [ - "bytes 1.0.0", + "bytes", "chrono", "hex", "http", - "http-body 0.4.0", + "http-body", "ring", "serde", - "serde_urlencoded 0.7.0", + "serde_urlencoded", ] [[package]] @@ -76,12 +56,6 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.0.0" @@ -115,8 +89,7 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -136,26 +109,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] -name = "dtoa" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" - -[[package]] -name = "dynamo-it" +name = "dynamo-helloworld" version = "0.1.0" dependencies = [ - "auth", "aws-hyper", - "bytes 1.0.0", "dynamodb", "http", - "hyper 0.14.2", - "io-v0", "operation", - "rand 0.7.3", - "smithy-types", - "tokio 1.0.1", + "tokio", ] [[package]] @@ -163,7 +124,7 @@ name = "dynamodb" version = "0.0.1" dependencies = [ "auth", - "bytes 1.0.0", + "bytes", "http", "operation", "rand 0.7.3", @@ -173,12 +134,6 @@ dependencies = [ "smithy-types", ] -[[package]] -name = "eliza_error" -version = "0.99.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1037d8a172e26e7c3178e0af0d21515e56f8c85fb1c637cfbd31abbb237c31" - [[package]] name = "fnv" version = "1.0.7" @@ -207,25 +162,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" dependencies = [ "matches", - "percent-encoding 2.1.0", -] - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", + "percent-encoding", ] -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futures-channel" version = "0.3.8" @@ -287,33 +226,13 @@ dependencies = [ "wasi 0.10.0+wasi-snapshot-preview1", ] -[[package]] -name = "h2" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio 0.2.24", - "tokio-util 0.3.1", - "tracing", - "tracing-futures", -] - [[package]] name = "h2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" dependencies = [ - "bytes 1.0.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -321,8 +240,8 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.0.1", - "tokio-util 0.6.1", + "tokio", + "tokio-util", "tracing", "tracing-futures", ] @@ -354,28 +273,18 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" dependencies = [ - "bytes 1.0.0", + "bytes", "fnv", "itoa", ] -[[package]] -name = "http-body" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" -dependencies = [ - "bytes 0.5.6", - "http", -] - [[package]] name = "http-body" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" dependencies = [ - "bytes 1.0.0", + "bytes", "http", ] @@ -391,49 +300,25 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" -[[package]] -name = "hyper" -version = "0.13.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ad767baac13b44d4529fcf58ba2cd0995e36e7b435bc5b039de6f47e880dbf" -dependencies = [ - "bytes 0.5.6", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.2.7", - "http", - "http-body 0.3.1", - "httparse", - "httpdate", - "itoa", - "pin-project 1.0.4", - "socket2", - "tokio 0.2.24", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" dependencies = [ - "bytes 1.0.0", + "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.0", + "h2", "http", - "http-body 0.4.0", + "http-body", "httparse", "httpdate", "itoa", "pin-project 1.0.4", "socket2", - "tokio 1.0.1", + "tokio", "tower-service", "tracing", "want", @@ -445,24 +330,13 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.0.0", - "hyper 0.14.2", + "bytes", + "hyper", "native-tls", - "tokio 1.0.1", + "tokio", "tokio-native-tls", ] -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.6.0" @@ -482,27 +356,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "io-v0" -version = "0.1.0" -dependencies = [ - "aws-sigv4 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "http", - "http-body 0.3.1", - "hyper 0.13.9", - "pin-utils", - "tokio 0.2.24", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - [[package]] name = "itoa" version = "0.4.6" @@ -518,16 +371,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -570,25 +413,6 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - [[package]] name = "mio" version = "0.7.7" @@ -597,44 +421,9 @@ checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" dependencies = [ "libc", "log", - "miow 0.3.6", + "miow", "ntapi", - "winapi 0.3.9", -] - -[[package]] -name = "mio-named-pipes" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" -dependencies = [ - "log", - "mio 0.6.23", - "miow 0.3.6", - "winapi 0.3.9", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio 0.6.23", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "winapi", ] [[package]] @@ -644,7 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -665,24 +454,13 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "ntapi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -758,11 +536,11 @@ name = "operation" version = "0.1.0" dependencies = [ "auth", - "bytes 1.0.0", + "bytes", "http", - "http-body 0.4.0", + "http-body", "pin-project 1.0.4", - "tower 0.4.2", + "tower", ] [[package]] @@ -787,15 +565,9 @@ dependencies = [ "libc", "redox_syscall 0.1.57", "smallvec", - "winapi 0.3.9", + "winapi", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -842,12 +614,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pin-project-lite" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" - [[package]] name = "pin-project-lite" version = "0.2.0" @@ -992,7 +758,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1007,7 +773,7 @@ dependencies = [ "spin", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1023,7 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1086,18 +852,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" -dependencies = [ - "dtoa", - "itoa", - "serde", - "url", -] - [[package]] name = "serde_urlencoded" version = "0.7.0" @@ -1154,7 +908,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall 0.1.57", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1185,57 +939,7 @@ dependencies = [ "rand 0.8.1", "redox_syscall 0.2.4", "remove_dir_all", - "winapi 0.3.9", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", -] - -[[package]] -name = "tinyvec" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "iovec", - "lazy_static", - "libc", - "memchr", - "mio 0.6.23", - "mio-named-pipes", - "mio-uds", - "num_cpus", - "pin-project-lite 0.1.11", - "signal-hook-registry", - "slab", - "tokio-macros 0.2.6", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1245,28 +949,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d258221f566b6c803c7b4714abadc080172b272090cdc5e244a6d4dd13c3a6bd" dependencies = [ "autocfg", - "bytes 1.0.0", + "bytes", "libc", "memchr", - "mio 0.7.7", + "mio", "num_cpus", "once_cell", "parking_lot", - "pin-project-lite 0.2.0", + "pin-project-lite", "signal-hook-registry", - "tokio-macros 1.0.0", - "winapi 0.3.9", -] - -[[package]] -name = "tokio-macros" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "tokio-macros", + "winapi", ] [[package]] @@ -1287,7 +980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", - "tokio 1.0.1", + "tokio", ] [[package]] @@ -1297,22 +990,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4cdeb73537e63f98adcd73138af75e3f368ccaecffaa29d7eb61b9f5a440457" dependencies = [ "futures-core", - "pin-project-lite 0.2.0", - "tokio 1.0.1", -] - -[[package]] -name = "tokio-util" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" -dependencies = [ - "bytes 0.5.6", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.1.11", - "tokio 0.2.24", + "pin-project-lite", + "tokio", ] [[package]] @@ -1321,33 +1000,15 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ae4751faa60b9f96dd8344d74592e5a17c0c9a220413dbc6942d14139bbfcc" dependencies = [ - "bytes 1.0.0", + "bytes", "futures-core", "futures-sink", "log", - "pin-project-lite 0.2.0", - "tokio 1.0.1", + "pin-project-lite", + "tokio", "tokio-stream", ] -[[package]] -name = "tower" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3169017c090b7a28fce80abaad0ab4f5566423677c9331bb320af7e49cfe62" -dependencies = [ - "futures-core", - "tower-buffer", - "tower-discover", - "tower-layer", - "tower-limit", - "tower-load-shed", - "tower-retry", - "tower-service", - "tower-timeout", - "tower-util", -] - [[package]] name = "tower" version = "0.4.2" @@ -1362,120 +1023,18 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-buffer" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a" -dependencies = [ - "futures-core", - "pin-project 0.4.27", - "tokio 0.2.24", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-discover" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6b5000c3c54d269cc695dff28136bb33d08cbf1df2c48129e143ab65bf3c2a" -dependencies = [ - "futures-core", - "pin-project 0.4.27", - "tower-service", -] - [[package]] name = "tower-layer" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" -[[package]] -name = "tower-limit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c3040c5dbed68abffaa0d4517ac1a454cd741044f33ab0eefab6b8d1361404" -dependencies = [ - "futures-core", - "pin-project 0.4.27", - "tokio 0.2.24", - "tower-layer", - "tower-load", - "tower-service", -] - -[[package]] -name = "tower-load" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc79fc3afd07492b7966d7efa7c6c50f8ed58d768a6075dd7ae6591c5d2017b" -dependencies = [ - "futures-core", - "log", - "pin-project 0.4.27", - "tokio 0.2.24", - "tower-discover", - "tower-service", -] - -[[package]] -name = "tower-load-shed" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f021e23900173dc315feb4b6922510dae3e79c689b74c089112066c11f0ae4e" -dependencies = [ - "futures-core", - "pin-project 0.4.27", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-retry" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6727956aaa2f8957d4d9232b308fe8e4e65d99db30f42b225646e86c9b6a952" -dependencies = [ - "futures-core", - "pin-project 0.4.27", - "tokio 0.2.24", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-service" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" -[[package]] -name = "tower-timeout" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "127b8924b357be938823eaaec0608c482d40add25609481027b96198b2e4b31e" -dependencies = [ - "pin-project 0.4.27", - "tokio 0.2.24", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-util" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1093c19826d33807c72511e68f73b4a0469a3f22c2bd5f7d5212178b4b89674" -dependencies = [ - "futures-core", - "futures-util", - "pin-project 0.4.27", - "tower-service", -] - [[package]] name = "tracing" version = "0.1.22" @@ -1484,7 +1043,7 @@ checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.0", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -1525,24 +1084,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-xid" version = "0.2.1" @@ -1555,17 +1096,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "vcpkg" version = "0.2.11" @@ -1658,12 +1188,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -1674,12 +1198,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1691,13 +1209,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.toml b/aws/sdk/examples/dynamo-helloworld/Cargo.toml new file mode 100644 index 0000000000..405a4f2201 --- /dev/null +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "dynamo-helloworld" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dev-dependencies] +dynamodb = { version = "0.0.1", path = "../../build/aws-sdk/dynamodb" } +aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } +operation = { path = "../../build/aws-sdk/operation" } +tokio = { version = "1", features = ["full"] } +http = "0.2.3" diff --git a/aws/sdk/dynamo-it/docker-compose.yml b/aws/sdk/examples/dynamo-helloworld/docker-compose.yml similarity index 100% rename from aws/sdk/dynamo-it/docker-compose.yml rename to aws/sdk/examples/dynamo-helloworld/docker-compose.yml diff --git a/aws/sdk/dynamo-it/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs similarity index 99% rename from aws/sdk/dynamo-it/src/main.rs rename to aws/sdk/examples/dynamo-helloworld/src/main.rs index 720ec2a39d..3f8e77f74c 100644 --- a/aws/sdk/dynamo-it/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -5,16 +5,10 @@ use std::error::Error; - - - use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; use http::Uri; use operation::endpoint::StaticEndpoint; - - - #[tokio::main] async fn main() -> Result<(), Box> { let config = dynamodb::Config::builder() diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGeneratorTest.kt index 6fd6c3267b..627c5d0d0c 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/config/ServiceConfigGeneratorTest.kt @@ -59,6 +59,7 @@ internal class ServiceConfigGeneratorTest { ServiceConfig.ConfigImpl -> emptySection ServiceConfig.BuilderStruct -> writable { rust("config_field: Option") } ServiceConfig.BuilderImpl -> emptySection + ServiceConfig.BuilderPreamble -> emptySection ServiceConfig.BuilderBuild -> writable { rust("config_field: self.config_field.unwrap_or_default(),") } } } From c794581463e517338536cce594ee8d46f601fd67 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 19 Jan 2021 10:31:05 -0500 Subject: [PATCH 16/50] Add DynamoDB Readme --- aws/sdk/examples/dynamo-helloworld/Cargo.toml | 2 +- aws/sdk/examples/dynamo-helloworld/README.md | 15 +++++++++++++++ aws/sdk/examples/dynamo-helloworld/src/main.rs | 11 +++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 aws/sdk/examples/dynamo-helloworld/README.md diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.toml b/aws/sdk/examples/dynamo-helloworld/Cargo.toml index 405a4f2201..6b12e3ce13 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.toml +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dev-dependencies] +[dependencies] dynamodb = { version = "0.0.1", path = "../../build/aws-sdk/dynamodb" } aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } operation = { path = "../../build/aws-sdk/operation" } diff --git a/aws/sdk/examples/dynamo-helloworld/README.md b/aws/sdk/examples/dynamo-helloworld/README.md new file mode 100644 index 0000000000..a4069339ca --- /dev/null +++ b/aws/sdk/examples/dynamo-helloworld/README.md @@ -0,0 +1,15 @@ +# DynamoDB Hello World Example +This repo has a simple hello-world example for DynamoDB that will create a table if it doesn't exist & list tables present in the database. + +By default, the code is written to target DynamoDB local—A docker compose file is provided for convenience. Usage: + +``` +docker-compose up -d +cargo run +``` + +## Running against real DynamoDB + +This hasn't been tested, but you'd need to: +- Remove the endpoint provider override +- Set real credentials (currently only static credentials are supported) diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 3f8e77f74c..6524d37f6a 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -50,5 +50,16 @@ async fn main() -> Result<(), Box> { Err(failed) => println!("failed to create table: {:?}", failed) } } + + let list_tables = dynamodb::operation::ListTables::builder().build(&config); + + let response = client.call(list_tables).await; + match response { + Ok(output) => { + println!("tables: {:?}", output.parsed.table_names.unwrap_or_default()); + }, + Err(e) => panic!("err: {:?}", e.error()), + }; + Ok(()) } From ee6bf85f49b51da77e7c256901d14bdf5ff6e918 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 11:37:48 -0500 Subject: [PATCH 17/50] Fix signing --- aws/rust-runtime/aws-hyper/Cargo.toml | 1 + aws/rust-runtime/aws-hyper/src/lib.rs | 49 +++------ aws/rust-runtime/operation/src/endpoint.rs | 6 ++ aws/rust-runtime/operation/src/lib.rs | 1 + aws/sdk/build.gradle.kts | 4 +- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 101 +++++++++++++++++- aws/sdk/examples/dynamo-helloworld/Cargo.toml | 2 + .../examples/dynamo-helloworld/src/main.rs | 11 +- 8 files changed, 134 insertions(+), 41 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 67adc582d4..413fbb2c4b 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" hyper = { version = "0.14.2", features = ["client", "http1", "http2"] } tower = "0.4.2" operation = { path = "../operation" } +middleware-tracing = { path = "../middleware-tracing" } hyper-tls = "0.5.0" auth = { path = "../auth" } http = "0.2.3" diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 2a55d66ac6..21a7f64fda 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -48,6 +48,14 @@ impl Client, SdkBody>> { } } +impl Client { + pub fn with_tracing(self) -> Client> { + Client { + inner: RawRequestLogging { inner: self.inner }, + } + } +} + impl Client where S: Service, Response = http::Response> + Clone, @@ -64,8 +72,8 @@ where let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); let mut ready_service = ServiceBuilder::new() - .layer(signer) .layer(endpoint_resolver) + .layer(signer) .layer(DispatchLayer) .service(ready_service); // TODO: enable operations to specify their own extra middleware to add @@ -118,6 +126,7 @@ where use http_body::Body; use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; +use middleware_tracing::RawRequestLogging; use operation::endpoint::EndpointMiddleware; use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; use operation::signing_middleware::SigningMiddleware; @@ -140,14 +149,17 @@ mod test { use crate::{read_body, Client}; use auth::Credentials; use bytes::Bytes; + use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; use hyper::service::service_fn; use operation::endpoint::StaticEndpoint; use operation::signing_middleware::SigningConfigExt; use operation::{Operation, ParseHttpResponse, SdkBody}; use pin_utils::core_reexport::fmt::Formatter; + use pin_utils::core_reexport::time::Duration; use std::error::Error; use std::sync::{Arc, Mutex}; + use std::time::UNIX_EPOCH; #[derive(Clone)] struct TestOperationParser; @@ -193,7 +205,8 @@ mod test { region: "some-region".into(), }, auth::RequestConfig { - request_ts: || std::time::SystemTime::now(), + // 1/20/2021 + request_ts: || UNIX_EPOCH + Duration::new(1611160427, 0), }, )); use operation::signing_middleware::CredentialProviderExt; @@ -212,35 +225,6 @@ mod test { response_handler: Box::new(TestOperationParser), }; - /*let operation = Operation { - request: operation::Request { - base: Request::builder() - .uri("/some_url") - .body(SdkBody::from("Hello")) - .unwrap(), - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - service: "svc".to_string(), - region: "region".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), - }, - double_uri_encode: false, - normalize_uri_path: true, - omit_session_token: false, - }), - credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), - endpoint_config: Box::new(StaticEndpoint::from_service_region( - "dynamodb", - "us-east-1", - )), - }, - response_handler: Box::new(TestOperationParser), - };*/ - let test_request: Arc>>> = Arc::new(Mutex::new(None)); let http_service = service_fn(|request: Request| async { let mut request = request; @@ -264,8 +248,9 @@ mod test { .keys() .map(|it| it.as_str()) .collect::>(), - vec!["authorization", "x-amz-date"] + vec!["host", "authorization", "x-amz-date"] ); + assert_eq!(request.headers().get(AUTHORIZATION).unwrap(), "AWS4-HMAC-SHA256 Credential=access/20210120/some-region/some-service/aws4_request, SignedHeaders=host, Signature=f179c6899f0a11051a11dc1bb022252b0741953663bc5ff33dfa2abfed51e0b1"); } /* diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index bc7441ed3d..1c0270f30d 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -11,6 +11,7 @@ use http::uri::Uri; use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; +use http::header::HOST; use std::sync::Arc; pub struct StaticEndpoint(http::Uri); @@ -99,6 +100,11 @@ impl OperationMiddleware for EndpointMiddleware { .endpoint_provider() .ok_or("missing endpoint provider")?; endpoint_provider.set_endpoint(&mut request.base.uri_mut()); + let uri = request.base.uri().host().unwrap().to_string(); + request.base.headers_mut().append( + HOST, + uri.parse().expect("host should be valid header value"), + ); Ok(()) } } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 68391538a7..21f6870038 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -13,6 +13,7 @@ use std::task::{Context, Poll}; type BodyError = Box; +#[derive(Debug)] pub enum SdkBody { Once(Option), } diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index 86dc3640ec..f448d13771 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -23,7 +23,7 @@ val awsServices = discoverServices() // TODO: smithy-http should be removed val runtimeModules = listOf("smithy-types", "smithy-http") val examples = listOf("dynamo-helloworld") -val awsModules = listOf("auth", "operation", "aws-hyper") +val awsModules = listOf("auth", "operation", "aws-hyper", "middleware-tracing") buildscript { val smithyVersion: String by project @@ -204,7 +204,7 @@ tasks.register("cargoClippy") { } tasks.register("dynamoIt") { - workingDir(projectDir.resolve("dynamo-it")) + workingDir(projectDir.resolve("examples/dynamo-helloworld")) // disallow warnings commandLine("cargo", "run") dependsOn("assemble") diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index b7f01ae2d5..ba416534bb 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -1,5 +1,25 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "auth" version = "0.1.0" @@ -24,6 +44,7 @@ dependencies = [ "http-body", "hyper", "hyper-tls", + "middleware-tracing", "operation", "pin-utils", "tower", @@ -112,8 +133,10 @@ checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" name = "dynamo-helloworld" version = "0.1.0" dependencies = [ + "auth", "aws-hyper", "dynamodb", + "env_logger", "http", "operation", "tokio", @@ -134,6 +157,19 @@ dependencies = [ "smithy-types", ] +[[package]] +name = "env_logger" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "fnv" version = "1.0.7" @@ -300,6 +336,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.2" @@ -413,6 +455,16 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "middleware-tracing" +version = "0.1.0" +dependencies = [ + "http", + "tower", + "tracing", + "tracing-futures", +] + [[package]] name = "mio" version = "0.7.7" @@ -752,6 +804,24 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -942,6 +1012,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" +dependencies = [ + "lazy_static", +] + [[package]] name = "tokio" version = "1.0.1" @@ -1011,9 +1099,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed5c471f00236abe8c633860d8234646cb4993eaad7720844f79bb1b94e949b" +checksum = "5fd7b451959622e21de79261673d658a0944b835012c58c51878ea55957fb51a" dependencies = [ "futures-core", "futures-util", @@ -1204,6 +1292,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.toml b/aws/sdk/examples/dynamo-helloworld/Cargo.toml index 6b12e3ce13..6240cb1e0a 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.toml +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.toml @@ -10,5 +10,7 @@ edition = "2018" dynamodb = { version = "0.0.1", path = "../../build/aws-sdk/dynamodb" } aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } operation = { path = "../../build/aws-sdk/operation" } +auth = { path = "../../build/aws-sdk/auth" } tokio = { version = "1", features = ["full"] } http = "0.2.3" +env_logger = "0.8.2" diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 6524d37f6a..7509527516 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -8,16 +8,17 @@ use std::error::Error; use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; use http::Uri; use operation::endpoint::StaticEndpoint; +use env_logger::Env; +use auth::Credentials; #[tokio::main] async fn main() -> Result<(), Box> { + env_logger::init_from_env(Env::default().default_filter_or("trace")); let config = dynamodb::Config::builder() .region("us-east-1") - .endpoint_provider(StaticEndpoint::from_uri(Uri::from_static( - "http://localhost:8000", - ))) + .credentials_provider(Credentials::from_static("", "")) .build(); - let client = aws_hyper::Client::default(); + let client = aws_hyper::Client::default().with_tracing(); let list_tables = dynamodb::operation::ListTables::builder().build(&config); let response = client.call(list_tables).await; @@ -25,7 +26,7 @@ async fn main() -> Result<(), Box> { Ok(output) => { output.parsed.table_names.unwrap() }, - Err(e) => panic!("err: {:?}", e.error()), + Err(e) => panic!("err: {:?}", e), }; if tables.is_empty() { let create_table = CreateTable::builder() From b2445f274d0783147ab02ee13a36e231a0ce4896 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 11:40:35 -0500 Subject: [PATCH 18/50] Add tracing middleware --- .../middleware-tracing/Cargo.toml | 13 +++++++++ .../middleware-tracing/src/lib.rs | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 aws/rust-runtime/middleware-tracing/Cargo.toml create mode 100644 aws/rust-runtime/middleware-tracing/src/lib.rs diff --git a/aws/rust-runtime/middleware-tracing/Cargo.toml b/aws/rust-runtime/middleware-tracing/Cargo.toml new file mode 100644 index 0000000000..75abd0a24e --- /dev/null +++ b/aws/rust-runtime/middleware-tracing/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "middleware-tracing" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tracing = "0.1.22" +tower = "0.4.3" +http = "0.2.3" +tracing-futures = "0.2.4" diff --git a/aws/rust-runtime/middleware-tracing/src/lib.rs b/aws/rust-runtime/middleware-tracing/src/lib.rs new file mode 100644 index 0000000000..2ec96edc83 --- /dev/null +++ b/aws/rust-runtime/middleware-tracing/src/lib.rs @@ -0,0 +1,29 @@ +use std::fmt::Debug; +use std::task::{Context, Poll}; +use tower::Service; +use tracing::instrument::{Instrument, Instrumented}; +use tracing::{span, Level}; + +#[derive(Clone)] +pub struct RawRequestLogging { + pub inner: S, +} + +impl Service> for RawRequestLogging +where + B: Debug, + S: Service>, +{ + type Response = S::Response; + type Error = S::Error; + type Future = Instrumented; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: http::Request) -> Self::Future { + let span = span!(Level::TRACE, "request_dispatch", req = ?&req); + self.inner.call(req).instrument(span) + } +} From 0b099d984eb0a07316e990ffcdada9f8855bbdda Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 11:41:52 -0500 Subject: [PATCH 19/50] raise logging level --- aws/sdk/examples/dynamo-helloworld/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 7509527516..aeb317934d 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -13,7 +13,7 @@ use auth::Credentials; #[tokio::main] async fn main() -> Result<(), Box> { - env_logger::init_from_env(Env::default().default_filter_or("trace")); + env_logger::init_from_env(Env::default().default_filter_or("debug")); let config = dynamodb::Config::builder() .region("us-east-1") .credentials_provider(Credentials::from_static("", "")) From f1f25fd61eb4473ab08f759c6539bded1c7c80f9 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 12:02:56 -0500 Subject: [PATCH 20/50] environment variable provider --- aws/rust-runtime/auth/src/lib.rs | 23 ++++++++++++++----- .../examples/dynamo-helloworld/src/main.rs | 9 ++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index b81949c703..02c0e4cc94 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -30,10 +30,13 @@ pub struct Credentials { impl Credentials { /// Create a Credentials struct from static credentials - pub fn from_static(access_key_id: impl ToString, secret_access_key: impl ToString) -> Self { + pub fn from_static( + access_key_id: impl Into, + secret_access_key: impl Into, + ) -> Self { Credentials { - access_key_id: access_key_id.to_string(), - secret_access_key: secret_access_key.to_string(), + access_key_id: access_key_id.into(), + secret_access_key: secret_access_key.into(), session_token: None, expiration: None, } @@ -69,9 +72,17 @@ pub trait ProvideCredentials: Send + Sync { } pub fn default_provider() -> impl ProvideCredentials { - // todo: this should be a chain, maybe CRT? - // Determine what the minimum support is - Credentials::from_static("todo", "todo") + // TODO: this should be a chain based on the CRT + EnvironmentProvider +} + +struct EnvironmentProvider; +impl ProvideCredentials for EnvironmentProvider { + fn credentials(&self) -> Result { + let access_key = std::env::var("AWS_ACCESS_KEY_ID").map_err("Access key missing")?; + let secret_key = std::env::var("AWS_SECRET_ACCESS_KEY").map_err("Secrete key missing")?; + Ok(Credentials::from_static(access_key, secret_key)) + } } impl ProvideCredentials for Credentials { diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index aeb317934d..82e2945d55 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -6,17 +6,18 @@ use std::error::Error; use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; -use http::Uri; -use operation::endpoint::StaticEndpoint; use env_logger::Env; -use auth::Credentials; #[tokio::main] async fn main() -> Result<(), Box> { env_logger::init_from_env(Env::default().default_filter_or("debug")); let config = dynamodb::Config::builder() .region("us-east-1") - .credentials_provider(Credentials::from_static("", "")) + // By default, it will load credentials from the environment variables + // .credentials_provider(auth::Credentials::from_static("", "")) + // For DynamoDB local: + // use operation::endpoint::StaticEndpoint; + // .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static("http://localhost:8000"))) .build(); let client = aws_hyper::Client::default().with_tracing(); let list_tables = dynamodb::operation::ListTables::builder().build(&config); From 2e58049fb0ba29b21a93aafe657e0ac0d82274ab Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 12:04:45 -0500 Subject: [PATCH 21/50] update comment --- aws/sdk/examples/dynamo-helloworld/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 82e2945d55..fe9a9a6711 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -13,7 +13,7 @@ async fn main() -> Result<(), Box> { env_logger::init_from_env(Env::default().default_filter_or("debug")); let config = dynamodb::Config::builder() .region("us-east-1") - // By default, it will load credentials from the environment variables + // By default, it will load credentials from the environment variables (config file not supported) // .credentials_provider(auth::Credentials::from_static("", "")) // For DynamoDB local: // use operation::endpoint::StaticEndpoint; From 42c2061723406263bdd061298e5f63fd30384949 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 12:11:37 -0500 Subject: [PATCH 22/50] go back to defaulting to DDB local --- aws/rust-runtime/auth/src/lib.rs | 4 ++-- aws/sdk/examples/dynamo-helloworld/src/main.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 02c0e4cc94..7a50b61d88 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -79,8 +79,8 @@ pub fn default_provider() -> impl ProvideCredentials { struct EnvironmentProvider; impl ProvideCredentials for EnvironmentProvider { fn credentials(&self) -> Result { - let access_key = std::env::var("AWS_ACCESS_KEY_ID").map_err("Access key missing")?; - let secret_key = std::env::var("AWS_SECRET_ACCESS_KEY").map_err("Secrete key missing")?; + let access_key = std::env::var("AWS_ACCESS_KEY_ID").map_err(|_|"Access key missing")?; + let secret_key = std::env::var("AWS_SECRET_ACCESS_KEY").map_err(|_|"Secret key missing")?; Ok(Credentials::from_static(access_key, secret_key)) } } diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index fe9a9a6711..482dc919c2 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -6,18 +6,18 @@ use std::error::Error; use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; +use operation::endpoint::StaticEndpoint; use env_logger::Env; #[tokio::main] async fn main() -> Result<(), Box> { - env_logger::init_from_env(Env::default().default_filter_or("debug")); + env_logger::init_from_env(Env::default().default_filter_or("info")); let config = dynamodb::Config::builder() .region("us-east-1") - // By default, it will load credentials from the environment variables (config file not supported) - // .credentials_provider(auth::Credentials::from_static("", "")) - // For DynamoDB local: - // use operation::endpoint::StaticEndpoint; - // .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static("http://localhost:8000"))) + // To load credentials from environment variables, delete this line + .credentials_provider(auth::Credentials::from_static("", "")) + // To use real DynamoDB, delete this line: + .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static("http://localhost:8000"))) .build(); let client = aws_hyper::Client::default().with_tracing(); let list_tables = dynamodb::operation::ListTables::builder().build(&config); From 56ea4b1ec07996bb6fe655be4a431eeca3087872 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 14:31:20 -0500 Subject: [PATCH 23/50] Make requests clonable --- aws/rust-runtime/auth/src/lib.rs | 7 +-- aws/rust-runtime/aws-hyper/src/lib.rs | 6 +++ aws/rust-runtime/operation/src/endpoint.rs | 23 +++++----- aws/rust-runtime/operation/src/extensions.rs | 10 ----- aws/rust-runtime/operation/src/lib.rs | 40 +++++++++++++---- .../operation/src/signing_middleware.rs | 44 ++++++++++--------- .../amazon/smithy/rustsdk/EndpointConfig.kt | 2 +- .../amazon/smithy/rustsdk/SigningConfig.kt | 4 +- 8 files changed, 79 insertions(+), 57 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 7a50b61d88..f7045c7d55 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -60,7 +60,7 @@ impl Display for CredentialsProviderError { impl Error for CredentialsProviderError {} // TODO -type CredentialsError = Box; +type CredentialsError = Box; /// A credentials provider /// @@ -79,8 +79,9 @@ pub fn default_provider() -> impl ProvideCredentials { struct EnvironmentProvider; impl ProvideCredentials for EnvironmentProvider { fn credentials(&self) -> Result { - let access_key = std::env::var("AWS_ACCESS_KEY_ID").map_err(|_|"Access key missing")?; - let secret_key = std::env::var("AWS_SECRET_ACCESS_KEY").map_err(|_|"Secret key missing")?; + let access_key = std::env::var("AWS_ACCESS_KEY_ID").map_err(|_| "Access key missing")?; + let secret_key = + std::env::var("AWS_SECRET_ACCESS_KEY").map_err(|_| "Secret key missing")?; Ok(Credentials::from_static(access_key, secret_key)) } } diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 21a7f64fda..d473989422 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -199,6 +199,8 @@ mod test { request .config + .lock() + .unwrap() .insert_signing_config(auth::SigningConfig::default_config( auth::ServiceConfig { service: "some-service".into(), @@ -212,11 +214,15 @@ mod test { use operation::signing_middleware::CredentialProviderExt; request .config + .lock() + .unwrap() .insert_credentials_provider(Arc::new(Credentials::from_static("access", "secret"))); use operation::endpoint::EndpointProviderExt; request .config + .lock() + .unwrap() .insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( "http://localhost:8000", )))); diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index 1c0270f30d..b627dc5d66 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -95,17 +95,18 @@ impl EndpointProviderExt for Extensions { pub struct EndpointMiddleware; impl OperationMiddleware for EndpointMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let endpoint_provider: &Arc = request - .config - .endpoint_provider() - .ok_or("missing endpoint provider")?; - endpoint_provider.set_endpoint(&mut request.base.uri_mut()); - let uri = request.base.uri().host().unwrap().to_string(); - request.base.headers_mut().append( - HOST, - uri.parse().expect("host should be valid header value"), - ); - Ok(()) + request.augment(|request, extensions| { + let endpoint_provider: &Arc = extensions + .endpoint_provider() + .ok_or("missing endpoint provider")?; + endpoint_provider.set_endpoint(&mut request.uri_mut()); + let uri = request.uri().host().unwrap().to_string(); + request.headers_mut().append( + HOST, + uri.parse().expect("host should be valid header value"), + ); + Ok(()) + }) } } diff --git a/aws/rust-runtime/operation/src/extensions.rs b/aws/rust-runtime/operation/src/extensions.rs index 41693876cb..6d398c27ab 100644 --- a/aws/rust-runtime/operation/src/extensions.rs +++ b/aws/rust-runtime/operation/src/extensions.rs @@ -44,16 +44,6 @@ pub struct Extensions { map: Option>, } -/* -macro_rules! extension_trait { - ($name1:expr, $name2:expr, $t:ty) => {{ - trait $name1 { - - } - - }} -}*/ - impl Extensions { /// Create an empty `Extensions`. #[inline] diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 21f6870038..63940ba39a 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -9,6 +9,7 @@ use crate::extensions::Extensions; use http::{HeaderMap, HeaderValue, Response}; use std::error::Error; use std::pin::Pin; +use std::sync::{Arc, Mutex}; use std::task::{Context, Poll}; type BodyError = Box; @@ -49,6 +50,12 @@ impl SdkBody { } } } + + pub fn try_clone(&self) -> Option { + match self { + SdkBody::Once(bytes) => Some(SdkBody::Once(bytes.clone())), + } + } } impl From<&str> for SdkBody { @@ -77,23 +84,38 @@ pub struct Operation { pub struct Request { pub base: http::Request, - - pub config: Extensions, - // These could also be attached in as extensions, but explicit might be better. - // Having some explicit configurations as explicit fields doesn't preclude storing data as - // extensions in the future - // pub signing_config: SigningConfig, - // pub credentials_provider: Box, - // pub endpoint_config: Box, + pub config: Arc>, } impl Request { pub fn new(base: http::Request) -> Self { Request { base, - config: Extensions::new(), + config: Arc::new(Mutex::new(Extensions::new())), } } + + pub fn augment(&mut self, f: impl Fn(&mut http::Request, &Extensions) -> T) -> T { + let extensions = self.config.lock().unwrap(); + f(&mut self.base, &extensions) + } + + pub fn try_clone(&self) -> Option { + let cloned_body = self.base.body().try_clone()?; + let mut cloned_request = http::Request::builder() + .uri(self.base.uri().clone()) + .method(self.base.method()); + for (name, value) in self.base.headers() { + cloned_request = cloned_request.header(name, value) + } + let base = cloned_request + .body(cloned_body) + .expect("should be clonable"); + Some(Request { + base, + config: self.config.clone(), + }) + } } pub trait ParseHttpResponse { diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 702255970a..56f9fbbb21 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -66,27 +66,29 @@ impl CredentialProviderExt for Extensions { impl OperationMiddleware for SigningMiddleware { fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - let signing_config = request - .config - .signing_config() - .ok_or("Missing signing config")?; - let cred_provider = request - .config - .credentials_provider() - .ok_or("Missing credentials provider")?; - let creds = cred_provider.credentials()?; - let body = match request.base.body() { - SdkBody::Once(Some(bytes)) => bytes.clone(), - SdkBody::Once(None) => bytes::Bytes::new(), - // in the future, chan variants which will cause an error - }; - match signing_config { - SigningConfig::Http(config) => { - if let Err(e) = self.signer.sign(config, &creds, &mut request.base, body) { - return Err(e); + request.augment(|mut request, config| { + let signing_config = config.signing_config().ok_or("Missing signing config")?; + let cred_provider = config + .credentials_provider() + .ok_or("Missing credentials provider")?; + let creds = match cred_provider.credentials() { + Ok(creds) => creds, + Err(e) => return Err(e as _), + }; + let body = match request.body() { + SdkBody::Once(Some(bytes)) => bytes.clone(), + SdkBody::Once(None) => bytes::Bytes::new(), + // in the future, chan variants which will cause an error + }; + + match signing_config { + SigningConfig::Http(config) => { + if let Err(e) = self.signer.sign(config, &creds, &mut request, body) { + return Err(e as _); + } } - } - }; - Ok(()) + }; + Ok(()) + }) } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt index 6e02a5ce4f..18b7753355 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt @@ -66,7 +66,7 @@ class EndpointConfigPlugin(private val operationShape: OperationShape) : Operati rust( """ use operation::endpoint::EndpointProviderExt; - request.config.insert_endpoint_provider(_config.endpoint_provider.clone()); + request.config.lock().unwrap().insert_endpoint_provider(_config.endpoint_provider.clone()); """ ) } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt index 38a3e2b4ed..3feba9d393 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt @@ -41,7 +41,7 @@ class SigV4SigningPlugin(operationShape: OperationShape) : OperationCustomizatio rust( """ use operation::signing_middleware::SigningConfigExt; - request.config.insert_signing_config(auth::SigningConfig::default_config( + request.config.lock().unwrap().insert_signing_config(auth::SigningConfig::default_config( auth::ServiceConfig { service: _config.signing_service().into(), region: _config.region.clone().into() @@ -51,7 +51,7 @@ class SigV4SigningPlugin(operationShape: OperationShape) : OperationCustomizatio }, )); use operation::signing_middleware::CredentialProviderExt; - request.config.insert_credentials_provider(_config.credentials_provider.clone()); + request.config.lock().unwrap().insert_credentials_provider(_config.credentials_provider.clone()); """ ) } From f2429f0213b3f6a6a43634612c6d846d5c5098cf Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 14:48:52 -0500 Subject: [PATCH 24/50] Use fn once, remove unecessary mut --- aws/rust-runtime/operation/src/lib.rs | 2 +- .../rust/codegen/smithy/generators/BuilderGenerator.kt | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 63940ba39a..e3ba306319 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -95,7 +95,7 @@ impl Request { } } - pub fn augment(&mut self, f: impl Fn(&mut http::Request, &Extensions) -> T) -> T { + pub fn augment(&mut self, f: impl FnOnce(&mut http::Request, &Extensions) -> T) -> T { let extensions = self.config.lock().unwrap(); f(&mut self.base, &extensions) } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index 90b1429fc5..b5234e2e3b 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -78,14 +78,9 @@ class OperationInputBuilderGenerator( withBlock("let op = #T::new(", ");", outputSymbol) { coreBuilder(this) } - val mut = if (plugins.isEmpty()) { - "" - } else { - "mut" - } rust( """ - let $mut request = operation::Request::new(op.build_http_request().map(|body|operation::SdkBody::from(body))); + let request = operation::Request::new(op.build_http_request().map(|body|operation::SdkBody::from(body))); """ ) plugins.forEach { it.section(OperationSection.Plugin)(this) } From eaad21295402185176515eaecacbee39f52cee5c Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 15:50:07 -0500 Subject: [PATCH 25/50] Update middleware to operate on owned requests --- aws/rust-runtime/aws-hyper/src/lib.rs | 2 +- aws/rust-runtime/operation/src/endpoint.rs | 10 +++++----- aws/rust-runtime/operation/src/lib.rs | 15 ++++++++++++--- aws/rust-runtime/operation/src/middleware.rs | 16 ++++++++-------- .../operation/src/signing_middleware.rs | 4 ++-- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index d473989422..3177732614 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -190,7 +190,7 @@ mod test { } impl Error for TestError {}; - let mut request = operation::Request::new( + let request = operation::Request::new( Request::builder() .uri("/some_url") .body(SdkBody::from("Hello")) diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index b627dc5d66..642a7a2515 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -62,9 +62,9 @@ impl OperationMiddleware for T where T: ProvideEndpoint, { - fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { + fn apply(&self, mut request: crate::Request) -> Result> { self.set_endpoint(&mut request.base.uri_mut()); - Ok(()) + Ok(request) } } @@ -94,8 +94,8 @@ impl EndpointProviderExt for Extensions { /// Set the endpoint for a request based on the endpoint config pub struct EndpointMiddleware; impl OperationMiddleware for EndpointMiddleware { - fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { - request.augment(|request, extensions| { + fn apply(&self, request: crate::Request) -> Result> { + request.augment(|mut request, extensions| { let endpoint_provider: &Arc = extensions .endpoint_provider() .ok_or("missing endpoint provider")?; @@ -105,7 +105,7 @@ impl OperationMiddleware for EndpointMiddleware { HOST, uri.parse().expect("host should be valid header value"), ); - Ok(()) + Ok(request) }) } } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index e3ba306319..9f355c63f2 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -95,9 +95,18 @@ impl Request { } } - pub fn augment(&mut self, f: impl FnOnce(&mut http::Request, &Extensions) -> T) -> T { - let extensions = self.config.lock().unwrap(); - f(&mut self.base, &extensions) + pub fn augment( + self, + f: impl FnOnce(http::Request, &Extensions) -> Result, T>, + ) -> Result { + let base = { + let extensions = (&self.config).lock().unwrap(); + f(self.base, &extensions)? + }; + Ok(Request { + base, + config: self.config, + }) } pub fn try_clone(&self) -> Option { diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index bb5687f5af..95360f5ae6 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -11,7 +11,7 @@ use std::task::{Context, Poll}; use tower::{Layer, Service}; pub trait OperationMiddleware { - fn apply(&self, request: &mut crate::Request) -> Result<(), Box>; + fn apply(&self, request: crate::Request) -> Result>; } pub struct OperationRequestMiddlewareService { @@ -81,15 +81,15 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, mut req: crate::Request) -> Self::Future { - if let Err(e) = self + fn call(&mut self, req: crate::Request) -> Self::Future { + match self .middleware - .apply(&mut req) + .apply(req) .map_err(|e| S::Error::request_error(e)) { - return OperationMiddlewareFuture::Ready(Some(e)); + Err(e) => OperationMiddlewareFuture::Ready(Some(e)), + Ok(req) => OperationMiddlewareFuture::Inner(self.inner.call(req)), } - OperationMiddlewareFuture::Inner(self.inner.call(req)) } } @@ -203,12 +203,12 @@ mod test { #[derive(Clone)] struct AddHeader(String, String); impl OperationMiddleware for AddHeader { - fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { + fn apply(&self, mut request: crate::Request) -> Result> { request.base.headers_mut().append( HeaderName::from_str(&self.0).unwrap(), HeaderValue::from_str(&self.0).unwrap(), ); - Ok(()) + Ok(request) } } diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 56f9fbbb21..6bf98bdd2a 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -65,7 +65,7 @@ impl CredentialProviderExt for Extensions { } impl OperationMiddleware for SigningMiddleware { - fn apply(&self, request: &mut crate::Request) -> Result<(), Box> { + fn apply(&self, request: crate::Request) -> Result> { request.augment(|mut request, config| { let signing_config = config.signing_config().ok_or("Missing signing config")?; let cred_provider = config @@ -88,7 +88,7 @@ impl OperationMiddleware for SigningMiddleware { } } }; - Ok(()) + Ok(request) }) } } From d13a6ed57367f0b19a161c846567f247ace0322a Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 20 Jan 2021 17:46:59 -0500 Subject: [PATCH 26/50] Add retry policy --- aws/rust-runtime/aws-hyper/src/lib.rs | 9 ++-- aws/rust-runtime/operation/src/lib.rs | 16 +++++++- .../operation/src/retry_policy.rs | 41 +++++++++++++++++++ .../smithy/generators/BuilderGenerator.kt | 13 +++--- 4 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 aws/rust-runtime/operation/src/retry_policy.rs diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 3177732614..1fbbc1ff78 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -56,14 +56,16 @@ impl Client { } } + impl Client where S: Service, Response = http::Response> + Clone, S::Error: std::error::Error + 'static, { - pub async fn call(&self, input: Operation) -> Result, SdkError> + pub async fn call(&self, input: Operation) -> Result, SdkError> where O: ParseHttpResponse>, + Retry: RetryPolicy> { let ready_service = ReadyOneshot::new(self.inner.clone()) .await @@ -130,6 +132,7 @@ use middleware_tracing::RawRequestLogging; use operation::endpoint::EndpointMiddleware; use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; use operation::signing_middleware::SigningMiddleware; +use operation::retry_policy::RetryPolicy; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -155,8 +158,8 @@ mod test { use operation::endpoint::StaticEndpoint; use operation::signing_middleware::SigningConfigExt; use operation::{Operation, ParseHttpResponse, SdkBody}; - use pin_utils::core_reexport::fmt::Formatter; - use pin_utils::core_reexport::time::Duration; + use std::fmt::Formatter; + use std::time::Duration; use std::error::Error; use std::sync::{Arc, Mutex}; use std::time::UNIX_EPOCH; diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 9f355c63f2..b718f29733 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -4,6 +4,7 @@ pub mod endpoint; mod extensions; pub mod middleware; pub mod signing_middleware; +pub mod retry_policy; use crate::extensions::Extensions; use http::{HeaderMap, HeaderValue, Response}; @@ -77,9 +78,20 @@ impl From> for SdkBody { } // TODO: consider field privacy, builders, etc. -pub struct Operation { +pub struct Operation { pub request: Request, - pub response_handler: Box, + pub response_handler: H, + pub retry_policy: R +} + +impl Operation { + pub fn new(request: Request, response_handler: H) -> Self { + Operation { + request, + response_handler, + retry_policy: () + } + } } pub struct Request { diff --git a/aws/rust-runtime/operation/src/retry_policy.rs b/aws/rust-runtime/operation/src/retry_policy.rs new file mode 100644 index 0000000000..ac62ebebd2 --- /dev/null +++ b/aws/rust-runtime/operation/src/retry_policy.rs @@ -0,0 +1,41 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use std::time::Duration; + +pub enum RetryType { + /// This is a connection level error such as a socket timeout, socket connect error, + /// tls negotiation timeout etc... + /// + /// Typically these should never be applied for non-idempotent request types + /// since in this scenario, it's impossible to know whether the operation had + /// a side effect on the server. + TransientError, + + /// An error where the server explicitly told the client to back off, such as a 429 or 503 HTTP error. + ThrottlingError, + + /// Server error that isn't explicitly throttling but is considered by the client + /// to be something that should be retried. + ServerError, + + /// Doesn't count against any budgets. This could be something like a 401 challenge in Http. + ClientError, + + /// An explicit retry in a set duration. This allows waiters + /// to be a special case of retries + Explicit(Duration) +} + +pub trait RetryPolicy { + fn should_retry(&self, input: &T) -> Option; +} + +/// () is the default policy: never retry +impl RetryPolicy for () { + fn should_retry(&self, _: &T) -> Option { + None + } +} diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index b5234e2e3b..73eada50ba 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -24,6 +24,7 @@ import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.smithy.defaultValue import software.amazon.smithy.rust.codegen.smithy.isOptional +import software.amazon.smithy.rust.codegen.smithy.letIf import software.amazon.smithy.rust.codegen.smithy.makeOptional import software.amazon.smithy.rust.codegen.smithy.rustType import software.amazon.smithy.rust.codegen.util.dq @@ -66,10 +67,8 @@ class OperationInputBuilderGenerator( ) : BuilderGenerator(model, symbolProvider, shape.inputShape(model)) { override fun buildFn(implBlockWriter: RustWriter) { val fallibleBuilder = StructureGenerator.fallibleBuilder(shape.inputShape(model), symbolProvider) - val returnType = when (fallibleBuilder) { - true -> "Result<#T<#{T}>, String>" - false -> "#T<#T>" - } + val retryType = "()" + val returnType = "#T<#{T}, $retryType>".letIf(fallibleBuilder) { "Result<$it, String>" } val outputSymbol = symbolProvider.toSymbol(shape) implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) @@ -86,10 +85,10 @@ class OperationInputBuilderGenerator( plugins.forEach { it.section(OperationSection.Plugin)(this) } rust( """ - #T { + #T::new( request, - response_handler: Box::new(op) - } + op + ) """, RuntimeType.Operation(symbolProvider.config().runtimeConfig) ) From 1fb4cb32b08002c9b1fc10d7593abb058bd35baa Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Thu, 21 Jan 2021 09:59:00 -0500 Subject: [PATCH 27/50] Add region provider from environment --- aws/rust-runtime/auth/src/lib.rs | 55 ++++++------ aws/rust-runtime/operation/src/lib.rs | 7 +- aws/rust-runtime/operation/src/region.rs | 83 +++++++++++++++++++ .../operation/src/signing_middleware.rs | 25 ++++-- .../smithy/rustsdk/AwsCodegenDecorator.kt | 2 +- .../amazon/smithy/rustsdk/EndpointConfig.kt | 2 +- .../amazon/smithy/rustsdk/RegionConfig.kt | 45 ++++++++-- .../amazon/smithy/rustsdk/SigningConfig.kt | 12 +-- 8 files changed, 179 insertions(+), 52 deletions(-) create mode 100644 aws/rust-runtime/operation/src/region.rs diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index f7045c7d55..1071e2dd54 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -92,12 +92,12 @@ impl ProvideCredentials for Credentials { } } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Clone, Copy)] pub enum SigningAlgorithm { SigV4, } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Clone, Copy)] pub enum HttpSignatureType { /// A signature for a full http request should be computed, with header updates applied to the signing result. HttpRequestHeaders, @@ -111,25 +111,29 @@ pub enum SigningConfig { // Event Stream } -impl SigningConfig { - pub fn default_config(service_config: ServiceConfig, request_config: RequestConfig) -> Self { - SigningConfig::Http(HttpSigningConfig { +impl OperationSigningConfig { + pub fn default_config(service: &'static str) -> Self { + OperationSigningConfig { algorithm: SigningAlgorithm::SigV4, signature_type: HttpSignatureType::HttpRequestHeaders, - service_config, - request_config, + service: service.into(), double_uri_encode: false, normalize_uri_path: true, omit_session_token: false, - }) + } } } pub struct HttpSigningConfig { + pub operation_config: OperationSigningConfig, + pub request_config: RequestConfig +} + +#[derive(Clone, PartialEq, Eq)] +pub struct OperationSigningConfig { pub algorithm: SigningAlgorithm, pub signature_type: HttpSignatureType, - pub service_config: ServiceConfig, - pub request_config: RequestConfig, + pub service: Cow<'static, str>, pub double_uri_encode: bool, pub normalize_uri_path: bool, @@ -138,12 +142,8 @@ pub struct HttpSigningConfig { pub struct RequestConfig { // the request config must enable recomputing the timestamp for retries, etc. - pub request_ts: fn() -> SystemTime, -} - -pub struct ServiceConfig { - pub service: Cow<'static, str>, - pub region: Cow<'static, str>, + pub request_ts: SystemTime, + pub region: Cow<'static, str> } type SigningError = Box; @@ -165,11 +165,12 @@ impl HttpSigner { request: &mut http::Request, payload: impl AsRef<[u8]>, ) -> Result<(), SigningError> { - if signing_config.algorithm != SigningAlgorithm::SigV4 - || signing_config.double_uri_encode - || !signing_config.normalize_uri_path - || signing_config.omit_session_token - || signing_config.signature_type != HttpSignatureType::HttpRequestHeaders + let operation_config = &signing_config.operation_config; + if operation_config.algorithm != SigningAlgorithm::SigV4 + || operation_config.double_uri_encode + || !operation_config.normalize_uri_path + || operation_config.omit_session_token + || operation_config.signature_type != HttpSignatureType::HttpRequestHeaders { unimplemented!() } @@ -179,13 +180,13 @@ impl HttpSigner { secret_key: credentials.secret_access_key.clone(), security_token: credentials.session_token.clone(), }; - let date = (signing_config.request_config.request_ts)(); + let date = signing_config.request_config.request_ts; for (key, value) in aws_sigv4::sign_core( request, payload, &sigv4_creds, - &signing_config.service_config.region, - &signing_config.service_config.service, + &signing_config.request_config.region, + &signing_config.operation_config.service, date, ) { request @@ -199,6 +200,11 @@ impl HttpSigner { #[cfg(test)] mod test { + #[test] + fn hello() { + + } + /* use crate::{ Credentials, CredentialsProviderError, HttpSignatureType, HttpSigner, HttpSigningConfig, ProvideCredentials, RequestConfig, ServiceConfig, SigningAlgorithm, @@ -313,4 +319,5 @@ mod test { vec!["authorization", "x-amz-date"] ); } + */ } diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index b718f29733..816e088730 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -5,6 +5,7 @@ mod extensions; pub mod middleware; pub mod signing_middleware; pub mod retry_policy; +pub mod region; use crate::extensions::Extensions; use http::{HeaderMap, HeaderValue, Response}; @@ -109,11 +110,11 @@ impl Request { pub fn augment( self, - f: impl FnOnce(http::Request, &Extensions) -> Result, T>, + f: impl FnOnce(http::Request, &mut Extensions) -> Result, T>, ) -> Result { let base = { - let extensions = (&self.config).lock().unwrap(); - f(self.base, &extensions)? + let mut extensions = (&self.config).lock().unwrap(); + f(self.base, &mut extensions)? }; Ok(Request { base, diff --git a/aws/rust-runtime/operation/src/region.rs b/aws/rust-runtime/operation/src/region.rs new file mode 100644 index 0000000000..3217415d5e --- /dev/null +++ b/aws/rust-runtime/operation/src/region.rs @@ -0,0 +1,83 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use crate::extensions::Extensions; + +#[derive(Clone)] +pub struct Region(String); + +impl AsRef for Region { + fn as_ref(&self) -> &str { + &self.0 + } +} +impl Region { + pub fn new(region: impl Into) -> Self { + Region(region.into()) + } +} + +pub trait ProvideRegion { + fn region(&self) -> Option; +} + +impl ProvideRegion for &str { + fn region(&self) -> Option { + Some(Region((*self).into())) + } +} + +struct RegionEnvironment; + +impl ProvideRegion for RegionEnvironment { + fn region(&self) -> Option { + std::env::var("AWS_DEFAULT_REGION").map(Region::new).ok() + } +} + +pub fn default_provider() -> impl ProvideRegion { + RegionEnvironment +} + +pub struct SigningRegion(String); + +impl SigningRegion { + pub fn new(region: impl Into) -> Self { + SigningRegion(region.into()) + } + +} + +pub trait RegionExt { + fn request_region(&self) -> Option<&str>; + fn signing_region(&self) -> Option<&str>; +} + + +impl RegionExt for Extensions { + fn request_region(&self) -> Option<&str> { + self.get::().map(|reg|reg.0.as_str()) + } + + fn signing_region(&self) -> Option<&str>{ + self.get::().map(|reg|reg.0.as_str()).or_else(||self.request_region()) + } +} + +#[cfg(test)] +mod test { + use crate::extensions::Extensions; + use crate::region::{Region, RegionExt, SigningRegion}; + + #[test] + fn signing_region_fallback() { + let mut extensions = Extensions::new(); + extensions.insert(Region::new("aws-global")); + assert_eq!(extensions.signing_region(), Some("aws-global")); + + extensions.insert(SigningRegion::new("us-east-1")); + assert_eq!(extensions.signing_region(), Some("us-east-1")) + } +} diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 6bf98bdd2a..75fd2800b0 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -5,9 +5,11 @@ use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; use crate::SdkBody; -use auth::{HttpSigner, ProvideCredentials, SigningConfig}; +use auth::{HttpSigner, ProvideCredentials, SigningConfig, OperationSigningConfig, RequestConfig, HttpSigningConfig}; use std::error::Error; use std::sync::Arc; +use std::time::SystemTime; +use crate::region::RegionExt; #[derive(Clone)] pub struct SigningMiddleware { @@ -29,16 +31,16 @@ impl SigningMiddleware { } pub trait SigningConfigExt { - fn signing_config(&self) -> Option<&SigningConfig>; - fn insert_signing_config(&mut self, signing_config: SigningConfig) -> Option; + fn signing_config(&self) -> Option<&OperationSigningConfig>; + fn insert_signing_config(&mut self, signing_config: OperationSigningConfig) -> Option; } impl SigningConfigExt for Extensions { - fn signing_config(&self) -> Option<&SigningConfig> { + fn signing_config(&self) -> Option<&OperationSigningConfig> { self.get() } - fn insert_signing_config(&mut self, signing_config: SigningConfig) -> Option { + fn insert_signing_config(&mut self, signing_config: OperationSigningConfig) -> Option { self.insert(signing_config) } } @@ -67,7 +69,7 @@ impl CredentialProviderExt for Extensions { impl OperationMiddleware for SigningMiddleware { fn apply(&self, request: crate::Request) -> Result> { request.augment(|mut request, config| { - let signing_config = config.signing_config().ok_or("Missing signing config")?; + let operation_config = config.signing_config().ok_or("Missing signing config")?; let cred_provider = config .credentials_provider() .ok_or("Missing credentials provider")?; @@ -80,10 +82,19 @@ impl OperationMiddleware for SigningMiddleware { SdkBody::Once(None) => bytes::Bytes::new(), // in the future, chan variants which will cause an error }; + let region = config.signing_region().ok_or("Can't sign; No region defined")?.to_string(); + let request_config = RequestConfig { + request_ts: SystemTime::now(), // TODO: replace with Extensions.now(); + region: region.into() + }; + let signing_config = SigningConfig::Http(HttpSigningConfig { + operation_config: operation_config.clone(), + request_config + }); match signing_config { SigningConfig::Http(config) => { - if let Err(e) = self.signer.sign(config, &creds, &mut request, body) { + if let Err(e) = self.signer.sign(&config, &creds, &mut request, body) { return Err(e as _); } } 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 63e70f74af..002161664d 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 @@ -34,6 +34,6 @@ class AwsCodegenDecorator : RustCodegenDecorator { operation: OperationShape, baseCustomizations: List ): List { - return listOf(SigV4SigningPlugin(operation), EndpointConfigPlugin(operation)) + baseCustomizations + return listOf(SigV4SigningPlugin(operation), EndpointConfigPlugin(operation), RegionConfigPlugin(operation)) + baseCustomizations } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt index 18b7753355..00f3c79fc2 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt @@ -43,7 +43,7 @@ class EndpointConfigCustomization(private val protocolConfig: ProtocolConfig) : ServiceConfig.BuilderBuild -> rust( """endpoint_provider: self.endpoint_provider.unwrap_or_else(|| ::std::sync::Arc::new( - #T::from_service_region(${endpointPrefix.dq()}, ®ion) + #T::from_service_region(${endpointPrefix.dq()}, region.as_ref().expect("region must be specified")) ) ),""", StaticEndpoint(protocolConfig.runtimeConfig) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt index 2979f49a04..d5016b8b08 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt @@ -5,31 +5,41 @@ package software.amazon.smithy.rustsdk +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.Local +import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig class RegionConfig : ConfigCustomization() { override fun section(section: ServiceConfig) = writable { when (section) { - is ServiceConfig.ConfigStruct -> rust("pub region: String,") + is ServiceConfig.ConfigStruct -> rust("pub region: Option<#T::Region>,", Region) is ServiceConfig.ConfigImpl -> emptySection is ServiceConfig.BuilderStruct -> - rust("region: Option,") + rust("region: Option<#T::Region>,", Region) ServiceConfig.BuilderImpl -> rust( """ - pub fn region(mut self, region: impl ToString) -> Self { - self.region = Some(region.to_string()); + pub fn region(mut self, region: impl #T::ProvideRegion) -> Self { + self.region = region.region(); self } """, + Region ) ServiceConfig.BuilderPreamble -> rust( - // TODO: design a config that enables resolving the default region chain - // clone because the region is also used - """let region = self.region.unwrap_or_else(|| "us-east-1".to_string());""", + """ + use #1T::ProvideRegion; + let region = self.region.or_else(||#1T::default_provider().region()); + """, + Region ) ServiceConfig.BuilderBuild -> rust( """region: region.clone(),""", @@ -37,3 +47,24 @@ class RegionConfig : ConfigCustomization() { } } } + +class RegionConfigPlugin(private val operationShape: OperationShape) : OperationCustomization() { + override fun section(section: OperationSection): Writable { + return when (section) { + OperationSection.ImplBlock -> emptySection + OperationSection.Plugin -> writable { + rust( + """ + if let Some(region) = &_config.region { + request.config.lock().unwrap().insert(region.clone()); + + } + """ + ) + } + } + } +} + +val Operation = CargoDependency("operation", Local("../")) +val Region = RuntimeType("region", Operation, "operation") diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt index 3feba9d393..34cc81a16f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt @@ -41,15 +41,9 @@ class SigV4SigningPlugin(operationShape: OperationShape) : OperationCustomizatio rust( """ use operation::signing_middleware::SigningConfigExt; - request.config.lock().unwrap().insert_signing_config(auth::SigningConfig::default_config( - auth::ServiceConfig { - service: _config.signing_service().into(), - region: _config.region.clone().into() - }, - auth::RequestConfig { - request_ts: ||std::time::SystemTime::now() - }, - )); + request.config.lock().unwrap().insert_signing_config( + auth::OperationSigningConfig::default_config(_config.signing_service()) + ); use operation::signing_middleware::CredentialProviderExt; request.config.lock().unwrap().insert_credentials_provider(_config.credentials_provider.clone()); """ From 07b052baf20ac7904b5d1fddec9eefa987db49c0 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 22 Jan 2021 11:56:42 -0500 Subject: [PATCH 28/50] Lots more improvements --- aws/rust-runtime/auth/src/lib.rs | 16 +- aws/rust-runtime/aws-hyper/src/lib.rs | 218 +++++++++++------- aws/rust-runtime/operation/src/lib.rs | 20 +- aws/rust-runtime/operation/src/region.rs | 10 +- .../operation/src/retry_policy.rs | 2 +- .../operation/src/signing_middleware.rs | 49 ++-- 6 files changed, 199 insertions(+), 116 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 1071e2dd54..6ec4209acf 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -126,7 +126,7 @@ impl OperationSigningConfig { pub struct HttpSigningConfig { pub operation_config: OperationSigningConfig, - pub request_config: RequestConfig + pub request_config: RequestConfig, } #[derive(Clone, PartialEq, Eq)] @@ -143,7 +143,7 @@ pub struct OperationSigningConfig { pub struct RequestConfig { // the request config must enable recomputing the timestamp for retries, etc. pub request_ts: SystemTime, - pub region: Cow<'static, str> + pub region: Cow<'static, str>, } type SigningError = Box; @@ -163,8 +163,10 @@ impl HttpSigner { signing_config: &HttpSigningConfig, credentials: &Credentials, request: &mut http::Request, - payload: impl AsRef<[u8]>, - ) -> Result<(), SigningError> { + ) -> Result<(), SigningError> + where + B: AsRef<[u8]>, + { let operation_config = &signing_config.operation_config; if operation_config.algorithm != SigningAlgorithm::SigV4 || operation_config.double_uri_encode @@ -183,7 +185,7 @@ impl HttpSigner { let date = signing_config.request_config.request_ts; for (key, value) in aws_sigv4::sign_core( request, - payload, + request.body(), &sigv4_creds, &signing_config.request_config.region, &signing_config.operation_config.service, @@ -201,9 +203,7 @@ impl HttpSigner { #[cfg(test)] mod test { #[test] - fn hello() { - - } + fn hello() {} /* use crate::{ Credentials, CredentialsProviderError, HttpSignatureType, HttpSigner, HttpSigningConfig, diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 1fbbc1ff78..7099f36240 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -2,36 +2,48 @@ use bytes::{Buf, Bytes}; use hyper::Client as HyperClient; use operation::{middleware::OperationError, Operation, ParseHttpResponse, SdkBody}; use std::error::Error; -use tower::util::ReadyOneshot; -use tower::{Service, ServiceBuilder}; +use tower::{Service, ServiceBuilder, Layer, ServiceExt}; -type ResponseBody = hyper::Body; +type SdkSuccess = _SdkSuccess; +type SdkError = _SdkError; #[derive(Debug)] -pub struct SdkResponse { - pub raw: http::Response, +pub struct _SdkSuccess { + pub raw: http::Response, pub parsed: O, } #[derive(Debug)] -pub enum SdkError { +pub enum _SdkError { + ConstructionFailure(Box), DispatchFailure(Box), ResponseError { - raw: http::Response, + raw: http::Response, err: Box, }, ServiceError { - raw: http::Response, + raw: http::Response, err: E, }, } +pub fn sdk_result( + parsed: Result, + raw: http::Response, +) -> Result<_SdkSuccess, _SdkError> { + match parsed { + Ok(parsed) => Ok(_SdkSuccess { raw, parsed }), + Err(err) => Err(_SdkError::ServiceError { raw, err }) + } +} + impl SdkError { pub fn error(self) -> Box { match self { SdkError::DispatchFailure(e) => e, SdkError::ResponseError { err, .. } => err, SdkError::ServiceError { err, .. } => Box::new(err), + SdkError::ConstructionFailure(e) => e } } } @@ -56,72 +68,117 @@ impl Client { } } +fn operation_error(o: OperationError) -> _SdkError where OE: Error + 'static { + match o { + OperationError::DispatchError(e) => _SdkError::DispatchFailure(Box::new(e)), + OperationError::ConstructionError(e) => _SdkError::ConstructionFailure(e) + } +} -impl Client -where - S: Service, Response = http::Response> + Clone, - S::Error: std::error::Error + 'static, +async fn load_response( + mut response: http::Response, + handler: &O, +) -> Result<_SdkSuccess, _SdkError> + where + B: http_body::Body + Unpin, + B: From, + B::Error: Error + 'static, + O: ParseHttpResponse>, +{ + if let Some(parsed_response) = handler.parse_unloaded(&mut response) { + return sdk_result(parsed_response, response); + } + + let body = match read_body(response.body_mut()).await { + Ok(body) => body, + Err(e) => { + return Err(_SdkError::ResponseError { + raw: response, + err: Box::new(e), + }); + } + }; + + let response = response.map(|_| Bytes::from(body)); + let parsed = handler.parse_loaded(&response); + return sdk_result(parsed, response.map(B::from)); +} + +pub struct LoadResponseMiddleware { + inner: S, +} + +pub struct ParseResponseLayer; + +impl Layer for ParseResponseLayer + where + S: Service, { - pub async fn call(&self, input: Operation) -> Result, SdkError> + type Service = LoadResponseMiddleware; + + fn layer(&self, inner: S) -> Self::Service { + LoadResponseMiddleware { inner } + } +} + +impl tower::Service> for LoadResponseMiddleware where - O: ParseHttpResponse>, - Retry: RetryPolicy> - { - let ready_service = ReadyOneshot::new(self.inner.clone()) - .await - .map_err(|e| SdkError::DispatchFailure(e.into()))?; + S: Service, Error=OperationError>, + OE: Error + 'static, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin, + B: From, + B::Error: Error + 'static, +{ + type Response = _SdkSuccess; + type Error = _SdkError; + type Future = Pin>>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx).map_err( operation_error) + } + fn call(&mut self, req: Operation) -> Self::Future { + let resp = self.inner.call(req.request); + let handler = req.response_handler; + let fut = async move { + match resp.await { + // TODO: split variant so they we don't retry missing credentials + Err(e) => Err(operation_error::(e)), + Ok(resp) => load_response(resp, &handler).await + } + }; + Box::pin(fut) + } +} + +impl Client + where + S: Service, Response=http::Response> + Clone, + S::Error: std::error::Error + 'static, + S::Future: 'static, +{ + pub async fn call( + &self, + input: Operation, + ) -> Result, SdkError> + where + O: ParseHttpResponse> + 'static, + Retry: RetryPolicy> + 'static, + { let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); - let mut ready_service = ServiceBuilder::new() + let mut inner = self.inner.clone(); + // TODO: reorder to call ready_and on the entire stack + let inner = inner.ready_and().await.map_err(|e|_SdkError::DispatchFailure(Box::new(e)))?; + let mut svc = ServiceBuilder::new() + .layer(ParseResponseLayer) .layer(endpoint_resolver) .layer(signer) .layer(DispatchLayer) - .service(ready_service); - // TODO: enable operations to specify their own extra middleware to add - let handler = input.response_handler; - let mut response: http::Response = ready_service - .call(input.request) - .await - .map_err(|e| match e { - OperationError::DispatchError(e) => SdkError::DispatchFailure(Box::new(e)), - OperationError::ConstructionError(e) => SdkError::DispatchFailure(e), - })?; - - let parsed = handler.parse_unloaded(&mut response); - let mut response = match parsed { - Some(Ok(r)) => { - return Ok(SdkResponse { - raw: response, - parsed: r, - }); - } - Some(Err(e)) => { - return Err(SdkError::ServiceError { - raw: response, - err: e, - }); - } - None => response, - }; - - let body = match read_body(response.body_mut()).await { - Ok(body) => body, - Err(e) => { - return Err(SdkError::ResponseError { - raw: response, - err: Box::new(e), - }); - } - }; - - let response = response.map(|_| Bytes::from(body)); - let parsed = handler.parse_loaded(&response); - let raw = response.map(hyper::Body::from); - match parsed { - Ok(parsed) => Ok(SdkResponse { raw, parsed }), - Err(err) => Err(SdkError::ServiceError { raw, err }), - } + .service(inner); + svc.call(input).await } } @@ -131,8 +188,11 @@ use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; use operation::endpoint::EndpointMiddleware; use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; -use operation::signing_middleware::SigningMiddleware; use operation::retry_policy::RetryPolicy; +use operation::signing_middleware::SigningMiddleware; +use std::future::Future; +use std::task::{Context, Poll}; +use std::pin::Pin; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -158,17 +218,18 @@ mod test { use operation::endpoint::StaticEndpoint; use operation::signing_middleware::SigningConfigExt; use operation::{Operation, ParseHttpResponse, SdkBody}; - use std::fmt::Formatter; - use std::time::Duration; use std::error::Error; + use std::fmt::Formatter; use std::sync::{Arc, Mutex}; + use std::time::Duration; use std::time::UNIX_EPOCH; #[derive(Clone)] struct TestOperationParser; + impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -191,7 +252,8 @@ mod test { unimplemented!() } } - impl Error for TestError {}; + impl Error for TestError {} + ; let request = operation::Request::new( Request::builder() @@ -204,16 +266,7 @@ mod test { .config .lock() .unwrap() - .insert_signing_config(auth::SigningConfig::default_config( - auth::ServiceConfig { - service: "some-service".into(), - region: "some-region".into(), - }, - auth::RequestConfig { - // 1/20/2021 - request_ts: || UNIX_EPOCH + Duration::new(1611160427, 0), - }, - )); + .insert_signing_config(auth::OperationSigningConfig::default_config("some-service")); use operation::signing_middleware::CredentialProviderExt; request .config @@ -231,7 +284,8 @@ mod test { )))); let operation = Operation { request, - response_handler: Box::new(TestOperationParser), + response_handler: TestOperationParser, + retry_policy: (), }; let test_request: Arc>>> = Arc::new(Mutex::new(None)); diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 816e088730..07eefa313a 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -3,9 +3,9 @@ use bytes::Bytes; pub mod endpoint; mod extensions; pub mod middleware; -pub mod signing_middleware; -pub mod retry_policy; pub mod region; +pub mod retry_policy; +pub mod signing_middleware; use crate::extensions::Extensions; use http::{HeaderMap, HeaderValue, Response}; @@ -53,6 +53,18 @@ impl SdkBody { } } + /// If possible, return a reference to this body as `&[u8]` + /// + /// If this SdkBody is NOT streaming, this will return the byte slab + /// If this SdkBody is streaming, this will return `None` + pub fn bytes(&self) -> Option<&[u8]> { + match self { + SdkBody::Once(Some(b)) => Some(&b), + SdkBody::Once(None) => Some(&[]), + // In the future, streaming variants will return `None` + } + } + pub fn try_clone(&self) -> Option { match self { SdkBody::Once(bytes) => Some(SdkBody::Once(bytes.clone())), @@ -82,7 +94,7 @@ impl From> for SdkBody { pub struct Operation { pub request: Request, pub response_handler: H, - pub retry_policy: R + pub retry_policy: R, } impl Operation { @@ -90,7 +102,7 @@ impl Operation { Operation { request, response_handler, - retry_policy: () + retry_policy: (), } } } diff --git a/aws/rust-runtime/operation/src/region.rs b/aws/rust-runtime/operation/src/region.rs index 3217415d5e..08b2ec9cde 100644 --- a/aws/rust-runtime/operation/src/region.rs +++ b/aws/rust-runtime/operation/src/region.rs @@ -47,7 +47,6 @@ impl SigningRegion { pub fn new(region: impl Into) -> Self { SigningRegion(region.into()) } - } pub trait RegionExt { @@ -55,14 +54,15 @@ pub trait RegionExt { fn signing_region(&self) -> Option<&str>; } - impl RegionExt for Extensions { fn request_region(&self) -> Option<&str> { - self.get::().map(|reg|reg.0.as_str()) + self.get::().map(|reg| reg.0.as_str()) } - fn signing_region(&self) -> Option<&str>{ - self.get::().map(|reg|reg.0.as_str()).or_else(||self.request_region()) + fn signing_region(&self) -> Option<&str> { + self.get::() + .map(|reg| reg.0.as_str()) + .or_else(|| self.request_region()) } } diff --git a/aws/rust-runtime/operation/src/retry_policy.rs b/aws/rust-runtime/operation/src/retry_policy.rs index ac62ebebd2..455a707509 100644 --- a/aws/rust-runtime/operation/src/retry_policy.rs +++ b/aws/rust-runtime/operation/src/retry_policy.rs @@ -26,7 +26,7 @@ pub enum RetryType { /// An explicit retry in a set duration. This allows waiters /// to be a special case of retries - Explicit(Duration) + Explicit(Duration), } pub trait RetryPolicy { diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 75fd2800b0..a0a042ce4b 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -4,12 +4,15 @@ */ use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; -use crate::SdkBody; -use auth::{HttpSigner, ProvideCredentials, SigningConfig, OperationSigningConfig, RequestConfig, HttpSigningConfig}; +use crate::region::RegionExt; +use auth::{ + HttpSigner, HttpSigningConfig, OperationSigningConfig, ProvideCredentials, RequestConfig, + SigningConfig, +}; +use http::Request; use std::error::Error; use std::sync::Arc; use std::time::SystemTime; -use crate::region::RegionExt; #[derive(Clone)] pub struct SigningMiddleware { @@ -32,7 +35,10 @@ impl SigningMiddleware { pub trait SigningConfigExt { fn signing_config(&self) -> Option<&OperationSigningConfig>; - fn insert_signing_config(&mut self, signing_config: OperationSigningConfig) -> Option; + fn insert_signing_config( + &mut self, + signing_config: OperationSigningConfig, + ) -> Option; } impl SigningConfigExt for Extensions { @@ -40,7 +46,10 @@ impl SigningConfigExt for Extensions { self.get() } - fn insert_signing_config(&mut self, signing_config: OperationSigningConfig) -> Option { + fn insert_signing_config( + &mut self, + signing_config: OperationSigningConfig, + ) -> Option { self.insert(signing_config) } } @@ -68,7 +77,7 @@ impl CredentialProviderExt for Extensions { impl OperationMiddleware for SigningMiddleware { fn apply(&self, request: crate::Request) -> Result> { - request.augment(|mut request, config| { + request.augment(|request, config| { let operation_config = config.signing_config().ok_or("Missing signing config")?; let cred_provider = config .credentials_provider() @@ -77,29 +86,37 @@ impl OperationMiddleware for SigningMiddleware { Ok(creds) => creds, Err(e) => return Err(e as _), }; - let body = match request.body() { - SdkBody::Once(Some(bytes)) => bytes.clone(), - SdkBody::Once(None) => bytes::Bytes::new(), - // in the future, chan variants which will cause an error - }; - let region = config.signing_region().ok_or("Can't sign; No region defined")?.to_string(); + let region = config + .signing_region() + .ok_or("Can't sign; No region defined")? + .to_string(); let request_config = RequestConfig { request_ts: SystemTime::now(), // TODO: replace with Extensions.now(); - region: region.into() + region: region.into(), }; let signing_config = SigningConfig::Http(HttpSigningConfig { operation_config: operation_config.clone(), - request_config + request_config, }); + let (parts, body) = request.into_parts(); + let signable_body = match body.bytes() { + Some(bytes) => bytes, + None => { + return Err("Cannot convert body to signing payload (body is streaming)".into()) + } // in the future, chan variants which will cause an error + }; + let mut signable_request = http::Request::from_parts(parts, signable_body); + match signing_config { SigningConfig::Http(config) => { - if let Err(e) = self.signer.sign(&config, &creds, &mut request, body) { + if let Err(e) = self.signer.sign(&config, &creds, &mut signable_request) { return Err(e as _); } } }; - Ok(request) + let (signed_parts, _) = signable_request.into_parts(); + Ok(Request::from_parts(signed_parts, body)) }) } } From 83a0e87dd54e8bdcc301595f8c8bebce141a8db9 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 22 Jan 2021 13:34:12 -0500 Subject: [PATCH 29/50] continued iteration on the service --- aws/rust-runtime/aws-hyper/Cargo.toml | 1 + aws/rust-runtime/aws-hyper/src/lib.rs | 155 +++++++++++------- .../operation/src/signing_middleware.rs | 5 +- 3 files changed, 103 insertions(+), 58 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 413fbb2c4b..3c5d342d11 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -20,3 +20,4 @@ pin-utils = "0.1.0" [dev-dependencies] tokio = { version = "1", features = ["full"]} +tower-test = "0.4.0" diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 7099f36240..69c94b21e5 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -2,10 +2,11 @@ use bytes::{Buf, Bytes}; use hyper::Client as HyperClient; use operation::{middleware::OperationError, Operation, ParseHttpResponse, SdkBody}; use std::error::Error; -use tower::{Service, ServiceBuilder, Layer, ServiceExt}; +use tower::{Layer, Service, ServiceBuilder, ServiceExt}; type SdkSuccess = _SdkSuccess; type SdkError = _SdkError; +type BoxError = Box; #[derive(Debug)] pub struct _SdkSuccess { @@ -33,7 +34,7 @@ pub fn sdk_result( ) -> Result<_SdkSuccess, _SdkError> { match parsed { Ok(parsed) => Ok(_SdkSuccess { raw, parsed }), - Err(err) => Err(_SdkError::ServiceError { raw, err }) + Err(err) => Err(_SdkError::ServiceError { raw, err }), } } @@ -43,7 +44,7 @@ impl SdkError { SdkError::DispatchFailure(e) => e, SdkError::ResponseError { err, .. } => err, SdkError::ServiceError { err, .. } => Box::new(err), - SdkError::ConstructionFailure(e) => e + SdkError::ConstructionFailure(e) => e, } } } @@ -68,10 +69,13 @@ impl Client { } } -fn operation_error(o: OperationError) -> _SdkError where OE: Error + 'static { +fn operation_error(o: OperationError) -> _SdkError +where + OE: Into, +{ match o { - OperationError::DispatchError(e) => _SdkError::DispatchFailure(Box::new(e)), - OperationError::ConstructionError(e) => _SdkError::ConstructionFailure(e) + OperationError::DispatchError(e) => _SdkError::DispatchFailure(e.into()), + OperationError::ConstructionError(e) => _SdkError::ConstructionFailure(e), } } @@ -79,11 +83,11 @@ async fn load_response( mut response: http::Response, handler: &O, ) -> Result<_SdkSuccess, _SdkError> - where - B: http_body::Body + Unpin, - B: From, - B::Error: Error + 'static, - O: ParseHttpResponse>, +where + B: http_body::Body + Unpin, + B: From, + B::Error: Error + 'static, + O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { return sdk_result(parsed_response, response); @@ -111,8 +115,8 @@ pub struct LoadResponseMiddleware { pub struct ParseResponseLayer; impl Layer for ParseResponseLayer - where - S: Service, +where + S: Service, { type Service = LoadResponseMiddleware; @@ -122,21 +126,21 @@ impl Layer for ParseResponseLayer } impl tower::Service> for LoadResponseMiddleware - where - S: Service, Error=OperationError>, - OE: Error + 'static, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin, - B: From, - B::Error: Error + 'static, +where + S: Service, Error = OperationError>, + OE: Into, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin, + B: From, + B::Error: Error + 'static, { type Response = _SdkSuccess; type Error = _SdkError; - type Future = Pin>>>; + type Future = Pin>>>; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx).map_err( operation_error) + self.inner.poll_ready(cx).map_err(operation_error) } fn call(&mut self, req: Operation) -> Self::Future { @@ -146,7 +150,7 @@ impl tower::Service> for LoadRe match resp.await { // TODO: split variant so they we don't retry missing credentials Err(e) => Err(operation_error::(e)), - Ok(resp) => load_response(resp, &handler).await + Ok(resp) => load_response(resp, &handler).await, } }; Box::pin(fut) @@ -154,24 +158,27 @@ impl tower::Service> for LoadRe } impl Client - where - S: Service, Response=http::Response> + Clone, - S::Error: std::error::Error + 'static, - S::Future: 'static, +where + S: Service, Response = http::Response> + Clone, + S::Error: Into + 'static, + S::Future: 'static, { pub async fn call( &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + 'static, - Retry: RetryPolicy> + 'static, + where + O: ParseHttpResponse> + 'static, + Retry: RetryPolicy> + 'static, { let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); let mut inner = self.inner.clone(); // TODO: reorder to call ready_and on the entire stack - let inner = inner.ready_and().await.map_err(|e|_SdkError::DispatchFailure(Box::new(e)))?; + let inner = inner + .ready_and() + .await + .map_err(|e| _SdkError::DispatchFailure(e.into()))?; let mut svc = ServiceBuilder::new() .layer(ParseResponseLayer) .layer(endpoint_resolver) @@ -191,8 +198,8 @@ use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; use operation::retry_policy::RetryPolicy; use operation::signing_middleware::SigningMiddleware; use std::future::Future; -use std::task::{Context, Poll}; use std::pin::Pin; +use std::task::{Context, Poll}; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -209,27 +216,61 @@ async fn read_body(body: B) -> Result, B::Error> { #[cfg(test)] mod test { - use crate::{read_body, Client}; + use crate::{BoxError, Client}; use auth::Credentials; use bytes::Bytes; use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; - use hyper::service::service_fn; use operation::endpoint::StaticEndpoint; + use operation::region::Region; use operation::signing_middleware::SigningConfigExt; use operation::{Operation, ParseHttpResponse, SdkBody}; + use pin_utils::core_reexport::task::{Context, Poll}; + use pin_utils::core_reexport::time::Duration; use std::error::Error; use std::fmt::Formatter; - use std::sync::{Arc, Mutex}; - use std::time::Duration; + use std::future::Future; + use std::pin::Pin; + use std::sync::{mpsc, Arc}; use std::time::UNIX_EPOCH; + #[derive(Clone)] + struct TestService { + f: fn(&http::Request) -> http::Response, + tx: mpsc::Sender>, + } + + impl TestService { + pub fn new( + f: fn(&http::Request) -> http::Response, + ) -> (Self, mpsc::Receiver>) { + let (tx, rx) = mpsc::channel(); + (TestService { f, tx }, rx) + } + } + + impl tower::Service> for TestService { + type Response = http::Response; + type Error = BoxError; + type Future = Pin>>>; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: Request) -> Self::Future { + let response = (self.f)(&req); + self.tx.send(req).unwrap(); + Box::pin(std::future::ready(Ok(response))) + } + } + #[derive(Clone)] struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -253,7 +294,6 @@ mod test { } } impl Error for TestError {} - ; let request = operation::Request::new( Request::builder() @@ -262,6 +302,17 @@ mod test { .unwrap(), ); + request + .config + .lock() + .unwrap() + .insert(Region::new("some-region")); + request + .config + .lock() + .unwrap() + .insert(UNIX_EPOCH + Duration::new(1611160427, 0)); + request .config .lock() @@ -288,23 +339,13 @@ mod test { retry_policy: (), }; - let test_request: Arc>>> = Arc::new(Mutex::new(None)); - let http_service = service_fn(|request: Request| async { - let mut request = request; - let body = read_body(request.body_mut()).await.unwrap(); - *(test_request.clone().lock().unwrap()) = Some(request.map(|_| Bytes::from(body))); - Result::, TestError>::Ok(Response::new(hyper::Body::from( - "hello!", - ))) - }); - let client = Client { - inner: http_service, - }; - let _ = client - .call(operation) - .await - .expect("operation should succeed"); - let request = test_request.lock().unwrap().take().unwrap(); + let (svc, rx) = TestService::new(|_req| http::Response::new(hyper::Body::from("hello!"))); + let client = Client { inner: svc }; + //handle.sen + let resp = client.call(operation).await; + println!("{:?}", resp); + let request = rx.try_recv().unwrap(); + assert_eq!( request .headers() diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index a0a042ce4b..02c273e109 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -91,7 +91,10 @@ impl OperationMiddleware for SigningMiddleware { .ok_or("Can't sign; No region defined")? .to_string(); let request_config = RequestConfig { - request_ts: SystemTime::now(), // TODO: replace with Extensions.now(); + request_ts: config + .get::() + .map(|t| t.clone()) + .unwrap_or_else(|| SystemTime::now()), // TODO: replace with Extensions.now(); region: region.into(), }; let signing_config = SigningConfig::Http(HttpSigningConfig { From 1f5e85b8ea5821389895576139ac702c3fc3090f Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 22 Jan 2021 15:55:15 -0500 Subject: [PATCH 30/50] retries! --- aws/rust-runtime/aws-hyper/Cargo.toml | 2 +- aws/rust-runtime/aws-hyper/src/lib.rs | 113 +++++++++++++++--- aws/rust-runtime/operation/src/endpoint.rs | 5 +- aws/rust-runtime/operation/src/middleware.rs | 12 +- .../operation/src/retry_policy.rs | 8 +- .../operation/src/signing_middleware.rs | 3 +- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 2 + .../codegen/smithy/SymbolMetadataProvider.kt | 2 +- .../generators/HttpProtocolGenerator.kt | 2 + 9 files changed, 121 insertions(+), 28 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 3c5d342d11..8106a31954 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] hyper = { version = "0.14.2", features = ["client", "http1", "http2"] } -tower = "0.4.2" +tower = { version = "0.4.2", features = ["retry", "buffer"] } operation = { path = "../operation" } middleware-tracing = { path = "../middleware-tracing" } hyper-tls = "0.5.0" diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 69c94b21e5..dfb9080e43 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -16,11 +16,11 @@ pub struct _SdkSuccess { #[derive(Debug)] pub enum _SdkError { - ConstructionFailure(Box), - DispatchFailure(Box), + ConstructionFailure(BoxError), + DispatchFailure(BoxError), ResponseError { raw: http::Response, - err: Box, + err: BoxError, }, ServiceError { raw: http::Response, @@ -86,7 +86,7 @@ async fn load_response( where B: http_body::Body + Unpin, B: From, - B::Error: Error + 'static, + B::Error: Error + Send + Sync + 'static, O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { @@ -108,10 +108,71 @@ where return sdk_result(parsed, response.map(B::from)); } +#[derive(Clone)] pub struct LoadResponseMiddleware { inner: S, } +pub struct RetryService { + inner: S, + retry_strategy: R, + _e: PhantomData, +} + +#[derive(Clone)] +struct RetryStrategy {} + +impl + tower::retry::Policy, Response, Error> + for RetryStrategy where R: RetryPolicy +{ + type Future = std::future::Ready; + + fn retry( + &self, + req: &Operation, + result: Result<&Response, &Error>, + ) -> Option { + let _ = req.retry_policy.should_retry(result); + None + } + + fn clone_request( + &self, + req: &Operation, + ) -> Option> { + let inner = req.request.try_clone()?; + Some(Operation { + request: inner, + response_handler: req.response_handler.clone(), + retry_policy: req.retry_policy.clone(), + }) + } +} + +/* +impl tower::Service> for RetryService where + S: Service>, + O: ParseHttpResponse + 'static, + R: RetryPolicy + Clone + 'static, + { + type Response = S::Response; + type Error = S::Error; + type Future = Pin>>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: Operation) -> Self::Future { + let fut = async { + self.inner.call(req).await + }; + Box::pin(fut) + + } +}*/ + pub struct ParseResponseLayer; impl Layer for ParseResponseLayer @@ -133,7 +194,7 @@ where O: ParseHttpResponse> + 'static, B: http_body::Body + Unpin, B: From, - B::Error: Error + 'static, + B::Error: Error + Send + Sync + 'static, { type Response = _SdkSuccess; type Error = _SdkError; @@ -157,49 +218,71 @@ where } } +/* +impl Layer for BufferLayer +where + S: Service + Send + 'static, + S::Future: Send, + S::Error: Into + Send + Sync, + Request: Send + 'static, + + */ + impl Client where - S: Service, Response = http::Response> + Clone, - S::Error: Into + 'static, - S::Future: 'static, + S: Service, Response = http::Response> + + Send + + Clone + + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { pub async fn call( &self, input: Operation, ) -> Result, SdkError> where - O: ParseHttpResponse> + 'static, - Retry: RetryPolicy> + 'static, + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); let mut inner = self.inner.clone(); // TODO: reorder to call ready_and on the entire stack - let inner = inner - .ready_and() - .await - .map_err(|e| _SdkError::DispatchFailure(e.into()))?; + /*let inner = inner + .ready_and() + .await + .map_err(|e| _SdkError::DispatchFailure(e.into()))?;*/ + //let retry_layer = RetryLayer::new(RetryStrategy {}); let mut svc = ServiceBuilder::new() + .retry(RetryStrategy {}) + //.buffer(100) .layer(ParseResponseLayer) .layer(endpoint_resolver) .layer(signer) .layer(DispatchLayer) .service(inner); + svc.call(input).await + //todo!() } } +use http::Response; use http_body::Body; use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; use operation::endpoint::EndpointMiddleware; use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; -use operation::retry_policy::RetryPolicy; +use operation::retry_policy::{RetryPolicy, RetryType}; use operation::signing_middleware::SigningMiddleware; +use pin_utils::core_reexport::time::Duration; use std::future::Future; +use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; +use tower::retry::{Policy, RetryLayer}; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index 642a7a2515..9f8684bce4 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -13,6 +13,7 @@ use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; use http::header::HOST; use std::sync::Arc; +use tower::BoxError; pub struct StaticEndpoint(http::Uri); @@ -62,7 +63,7 @@ impl OperationMiddleware for T where T: ProvideEndpoint, { - fn apply(&self, mut request: crate::Request) -> Result> { + fn apply(&self, mut request: crate::Request) -> Result { self.set_endpoint(&mut request.base.uri_mut()); Ok(request) } @@ -94,7 +95,7 @@ impl EndpointProviderExt for Extensions { /// Set the endpoint for a request based on the endpoint config pub struct EndpointMiddleware; impl OperationMiddleware for EndpointMiddleware { - fn apply(&self, request: crate::Request) -> Result> { + fn apply(&self, request: crate::Request) -> Result { request.augment(|mut request, extensions| { let endpoint_provider: &Arc = extensions .endpoint_provider() diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 95360f5ae6..3c1be5daec 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -9,11 +9,13 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use tower::{Layer, Service}; +type BoxError = Box; pub trait OperationMiddleware { - fn apply(&self, request: crate::Request) -> Result>; + fn apply(&self, request: crate::Request) -> Result; } +#[derive(Clone)] pub struct OperationRequestMiddlewareService { inner: S, middleware: M, @@ -44,7 +46,7 @@ where } pub trait RequestConstructionErr { - fn request_error(err: Box) -> Self; + fn request_error(err: Box) -> Self; } #[pin_project(project = EnumProj)] @@ -97,10 +99,12 @@ where /// /// It will also wrap the error type in OperationError to enable operation middleware /// reporting specific errors +#[derive(Clone)] pub struct DispatchMiddleware { inner: S, } +#[derive(Clone, Copy)] pub struct DispatchLayer; impl Layer for DispatchLayer @@ -117,11 +121,11 @@ where #[derive(Debug)] pub enum OperationError { DispatchError(E), - ConstructionError(Box), + ConstructionError(Box), } impl RequestConstructionErr for OperationError { - fn request_error(err: Box) -> Self { + fn request_error(err: Box) -> Self { OperationError::ConstructionError(err) } } diff --git a/aws/rust-runtime/operation/src/retry_policy.rs b/aws/rust-runtime/operation/src/retry_policy.rs index 455a707509..16c83a5039 100644 --- a/aws/rust-runtime/operation/src/retry_policy.rs +++ b/aws/rust-runtime/operation/src/retry_policy.rs @@ -29,13 +29,13 @@ pub enum RetryType { Explicit(Duration), } -pub trait RetryPolicy { - fn should_retry(&self, input: &T) -> Option; +pub trait RetryPolicy { + fn should_retry(&self, input: Result<&T, &E>) -> Option; } /// () is the default policy: never retry -impl RetryPolicy for () { - fn should_retry(&self, _: &T) -> Option { +impl RetryPolicy for () { + fn should_retry(&self, _: Result<&T, &E>) -> Option { None } } diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index 02c273e109..dc10f31044 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -13,6 +13,7 @@ use http::Request; use std::error::Error; use std::sync::Arc; use std::time::SystemTime; +use tower::BoxError; #[derive(Clone)] pub struct SigningMiddleware { @@ -76,7 +77,7 @@ impl CredentialProviderExt for Extensions { } impl OperationMiddleware for SigningMiddleware { - fn apply(&self, request: crate::Request) -> Result> { + fn apply(&self, request: crate::Request) -> Result { request.augment(|request, config| { let operation_config = config.signing_config().ok_or("Missing signing config")?; let cred_provider = config diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index ba416534bb..1654c0e09a 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -1106,6 +1106,8 @@ dependencies = [ "futures-core", "futures-util", "pin-project 1.0.4", + "tokio", + "tokio-stream", "tower-layer", "tower-service", "tracing", diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/SymbolMetadataProvider.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/SymbolMetadataProvider.kt index b2b190baf5..423870f563 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/SymbolMetadataProvider.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/SymbolMetadataProvider.kt @@ -91,7 +91,7 @@ class BaseSymbolMetadataProvider(base: RustSymbolProvider) : SymbolMetadataProvi } companion object { - private val defaultDerives = + val defaultDerives = listOf(RuntimeType.StdFmt("Debug"), RuntimeType.Std("cmp::PartialEq"), RuntimeType.Std("clone::Clone")) } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt index 74be1743e4..64bc46c96e 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt @@ -10,6 +10,7 @@ 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.shapes.StructureShape +import software.amazon.smithy.rust.codegen.rustlang.Derives import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rustBlock @@ -89,6 +90,7 @@ abstract class HttpProtocolGenerator( extras(operationWriter, operationShape) val operationName = symbolProvider.toSymbol(operationShape).name operationWriter.documentShape(operationShape, model) + Derives(setOf(RuntimeType.Std("clone::Clone"))).render(operationWriter) operationWriter.rustBlock("pub struct $operationName") { write("input: #T", inputSymbol) } From a0f7f6c1a95909f855fad9cd5264b682aa03cc4f Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 22 Jan 2021 16:42:00 -0500 Subject: [PATCH 31/50] Working retry support! --- aws/rust-runtime/aws-hyper/Cargo.toml | 1 + aws/rust-runtime/aws-hyper/src/lib.rs | 89 ++++++++--------- aws/rust-runtime/operation/src/endpoint.rs | 1 - aws/rust-runtime/operation/src/lib.rs | 12 ++- .../operation/src/signing_middleware.rs | 1 - aws/sdk/examples/dynamo-helloworld/Cargo.lock | 1 + .../examples/dynamo-helloworld/src/main.rs | 96 +++++++++++++------ 7 files changed, 123 insertions(+), 78 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 8106a31954..46e24aecdf 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -16,6 +16,7 @@ auth = { path = "../auth" } http = "0.2.3" bytes = "1" http-body = "0.4.0" +tokio = { version = "1", features = ["time"]} pin-utils = "0.1.0" [dev-dependencies] diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index dfb9080e43..97ee2d80cb 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -2,7 +2,7 @@ use bytes::{Buf, Bytes}; use hyper::Client as HyperClient; use operation::{middleware::OperationError, Operation, ParseHttpResponse, SdkBody}; use std::error::Error; -use tower::{Layer, Service, ServiceBuilder, ServiceExt}; +use tower::{Layer, Service, ServiceBuilder}; type SdkSuccess = _SdkSuccess; type SdkError = _SdkError; @@ -70,8 +70,8 @@ impl Client { } fn operation_error(o: OperationError) -> _SdkError -where - OE: Into, + where + OE: Into, { match o { OperationError::DispatchError(e) => _SdkError::DispatchFailure(e.into()), @@ -83,11 +83,11 @@ async fn load_response( mut response: http::Response, handler: &O, ) -> Result<_SdkSuccess, _SdkError> -where - B: http_body::Body + Unpin, - B: From, - B::Error: Error + Send + Sync + 'static, - O: ParseHttpResponse>, + where + B: http_body::Body + Unpin, + B: From, + B::Error: Error + Send + Sync + 'static, + O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { return sdk_result(parsed_response, response); @@ -113,28 +113,27 @@ pub struct LoadResponseMiddleware { inner: S, } -pub struct RetryService { - inner: S, - retry_strategy: R, - _e: PhantomData, -} - #[derive(Clone)] struct RetryStrategy {} impl - tower::retry::Policy, Response, Error> - for RetryStrategy where R: RetryPolicy +tower::retry::Policy, Response, Error> +for RetryStrategy where R: RetryPolicy { - type Future = std::future::Ready; + type Future = Pin>>; fn retry( &self, req: &Operation, result: Result<&Response, &Error>, ) -> Option { - let _ = req.retry_policy.should_retry(result); - None + let _resp = req.retry_policy.should_retry(result)?; + let next = self.clone(); + let fut = async move { + tokio::time::sleep(Duration::new(5, 0)).await; + next + }; + Some(Box::pin(fut)) } fn clone_request( @@ -176,8 +175,8 @@ impl tower::Service> for RetryService pub struct ParseResponseLayer; impl Layer for ParseResponseLayer -where - S: Service, + where + S: Service, { type Service = LoadResponseMiddleware; @@ -187,18 +186,18 @@ where } impl tower::Service> for LoadResponseMiddleware -where - S: Service, Error = OperationError>, - OE: Into, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin, - B: From, - B::Error: Error + Send + Sync + 'static, + where + S: Service, Error=OperationError>, + OE: Into, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin, + B: From, + B::Error: Error + Send + Sync + 'static, { type Response = _SdkSuccess; type Error = _SdkError; - type Future = Pin>>>; + type Future = Pin>>>; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx).map_err(operation_error) @@ -229,25 +228,25 @@ where */ impl Client -where - S: Service, Response = http::Response> + where + S: Service, Response=http::Response> + Send + Clone + 'static, - S::Error: Into + Send + Sync + 'static, - S::Future: Send + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { pub async fn call( &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); - let mut inner = self.inner.clone(); + let inner = self.inner.clone(); // TODO: reorder to call ready_and on the entire stack /*let inner = inner .ready_and() @@ -268,21 +267,18 @@ where } } -use http::Response; use http_body::Body; use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; use operation::endpoint::EndpointMiddleware; use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; -use operation::retry_policy::{RetryPolicy, RetryType}; +use operation::retry_policy::{RetryPolicy}; use operation::signing_middleware::SigningMiddleware; -use pin_utils::core_reexport::time::Duration; use std::future::Future; -use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; -use tower::retry::{Policy, RetryLayer}; +use pin_utils::core_reexport::time::Duration; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -335,7 +331,7 @@ mod test { impl tower::Service> for TestService { type Response = http::Response; type Error = BoxError; - type Future = Pin>>>; + type Future = Pin> + Send>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -352,8 +348,8 @@ mod test { struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -424,7 +420,6 @@ mod test { let (svc, rx) = TestService::new(|_req| http::Response::new(hyper::Body::from("hello!"))); let client = Client { inner: svc }; - //handle.sen let resp = client.call(operation).await; println!("{:?}", resp); let request = rx.try_recv().unwrap(); diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index 9f8684bce4..59cc3fc0e4 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -4,7 +4,6 @@ */ use core::convert::AsRef; -use std::error::Error; use std::str::FromStr; use http::uri::Uri; diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 07eefa313a..53366d7397 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -105,6 +105,14 @@ impl Operation { retry_policy: (), } } + + pub fn with_policy(self, retry_policy: R) -> Operation { + Operation { + request: self.request, + response_handler: self.response_handler, + retry_policy, + } + } } pub struct Request { @@ -170,8 +178,8 @@ pub trait ParseStrictResponse { } impl ParseHttpResponse for T -where - T: ParseStrictResponse, + where + T: ParseStrictResponse, { type Output = T::Output; diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index dc10f31044..da072c4cc8 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -10,7 +10,6 @@ use auth::{ SigningConfig, }; use http::Request; -use std::error::Error; use std::sync::Arc; use std::time::SystemTime; use tower::BoxError; diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index 1654c0e09a..a3f474cd82 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -47,6 +47,7 @@ dependencies = [ "middleware-tracing", "operation", "pin-utils", + "tokio", "tower", ] diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 482dc919c2..951a00fd52 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -5,9 +5,42 @@ use std::error::Error; -use dynamodb::{model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType}, operation::CreateTable}; -use operation::endpoint::StaticEndpoint; +use dynamodb::error::ListTablesError; +use dynamodb::output::ListTablesOutput; +use dynamodb::{ + model::{ + AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, + }, + operation::CreateTable, +}; use env_logger::Env; +use operation::endpoint::StaticEndpoint; +use operation::retry_policy::{RetryPolicy, RetryType}; +use tokio::time::Duration; +use aws_hyper::{_SdkSuccess, _SdkError}; + +#[derive(Clone)] +struct RetryIfNoTables; +impl RetryPolicy<_SdkSuccess, _SdkError> for RetryIfNoTables { + fn should_retry(&self, input: Result<&_SdkSuccess, &_SdkError>) -> Option { + match input { + Ok(list_tables) => { + if list_tables.parsed + .table_names + .as_ref() + .map(|t| t.len()) + .unwrap_or_default() + == 0 + { + Some(RetryType::Explicit(Duration::new(5, 0))) + } else { + None + } + } + _ => None, + } + } +} #[tokio::main] async fn main() -> Result<(), Box> { @@ -15,41 +48,47 @@ async fn main() -> Result<(), Box> { let config = dynamodb::Config::builder() .region("us-east-1") // To load credentials from environment variables, delete this line - .credentials_provider(auth::Credentials::from_static("", "")) + .credentials_provider(auth::Credentials::from_static( + "", + "", + )) // To use real DynamoDB, delete this line: - .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static("http://localhost:8000"))) + .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static( + "http://localhost:8000", + ))) .build(); let client = aws_hyper::Client::default().with_tracing(); - let list_tables = dynamodb::operation::ListTables::builder().build(&config); + let list_tables = dynamodb::operation::ListTables::builder() + .build(&config); + // For a custom retry policy: + // .with_policy(RetryIfNoTables); let response = client.call(list_tables).await; let tables = match response { - Ok(output) => { - output.parsed.table_names.unwrap() - }, + Ok(output) => output.parsed.table_names.unwrap(), Err(e) => panic!("err: {:?}", e), }; if tables.is_empty() { let create_table = CreateTable::builder() - .table_name("new_table") - .attribute_definitions(vec![AttributeDefinition::builder() - .attribute_name("ForumName") - .attribute_type(ScalarAttributeType::S) - .build()]) - .key_schema(vec![KeySchemaElement::builder() - .attribute_name("ForumName") - .key_type(KeyType::Hash) - .build()]) - .provisioned_throughput( - ProvisionedThroughput::builder() - .read_capacity_units(100) - .write_capacity_units(100) - .build(), - ) - .build(&config); + .table_name("new_table") + .attribute_definitions(vec![AttributeDefinition::builder() + .attribute_name("ForumName") + .attribute_type(ScalarAttributeType::S) + .build()]) + .key_schema(vec![KeySchemaElement::builder() + .attribute_name("ForumName") + .key_type(KeyType::Hash) + .build()]) + .provisioned_throughput( + ProvisionedThroughput::builder() + .read_capacity_units(100) + .write_capacity_units(100) + .build(), + ) + .build(&config); match client.call(create_table).await { Ok(created) => println!("table created! {:#?}", created.parsed), - Err(failed) => println!("failed to create table: {:?}", failed) + Err(failed) => println!("failed to create table: {:?}", failed), } } @@ -58,8 +97,11 @@ async fn main() -> Result<(), Box> { let response = client.call(list_tables).await; match response { Ok(output) => { - println!("tables: {:?}", output.parsed.table_names.unwrap_or_default()); - }, + println!( + "tables: {:?}", + output.parsed.table_names.unwrap_or_default() + ); + } Err(e) => panic!("err: {:?}", e.error()), }; From 4d52a529b8b0da20de860999d493a6054ae5c2c3 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 22 Jan 2021 17:04:00 -0500 Subject: [PATCH 32/50] More cleanups --- aws/rust-runtime/aws-hyper/src/lib.rs | 202 ++++++------------ aws/rust-runtime/operation/src/endpoint.rs | 4 +- aws/rust-runtime/operation/src/lib.rs | 4 +- aws/rust-runtime/operation/src/middleware.rs | 14 +- .../operation/src/signing_middleware.rs | 12 +- .../examples/dynamo-helloworld/src/main.rs | 19 +- 6 files changed, 98 insertions(+), 157 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 97ee2d80cb..7813b5f8d0 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -4,37 +4,41 @@ use operation::{middleware::OperationError, Operation, ParseHttpResponse, SdkBod use std::error::Error; use tower::{Layer, Service, ServiceBuilder}; -type SdkSuccess = _SdkSuccess; -type SdkError = _SdkError; type BoxError = Box; #[derive(Debug)] -pub struct _SdkSuccess { - pub raw: http::Response, +pub struct SdkSuccess { + pub raw: http::Response>, pub parsed: O, } #[derive(Debug)] -pub enum _SdkError { +pub enum SdkError { ConstructionFailure(BoxError), DispatchFailure(BoxError), ResponseError { - raw: http::Response, + raw: http::Response>, err: BoxError, }, ServiceError { - raw: http::Response, + raw: http::Response>, err: E, }, } -pub fn sdk_result( +pub fn sdk_result( parsed: Result, raw: http::Response, -) -> Result<_SdkSuccess, _SdkError> { +) -> Result, SdkError> { match parsed { - Ok(parsed) => Ok(_SdkSuccess { raw, parsed }), - Err(err) => Err(_SdkError::ServiceError { raw, err }), + Ok(parsed) => Ok(SdkSuccess { + raw: raw.map(|b| Box::new(b) as _), + parsed, + }), + Err(err) => Err(SdkError::ServiceError { + raw: raw.map(|b| Box::new(b) as _), + err, + }), } } @@ -69,25 +73,25 @@ impl Client { } } -fn operation_error(o: OperationError) -> _SdkError - where - OE: Into, +fn operation_error(o: OperationError) -> SdkError +where + OE: Into, { match o { - OperationError::DispatchError(e) => _SdkError::DispatchFailure(e.into()), - OperationError::ConstructionError(e) => _SdkError::ConstructionFailure(e), + OperationError::DispatchError(e) => SdkError::DispatchFailure(e.into()), + OperationError::ConstructionError(e) => SdkError::ConstructionFailure(e), } } async fn load_response( mut response: http::Response, handler: &O, -) -> Result<_SdkSuccess, _SdkError> - where - B: http_body::Body + Unpin, - B: From, - B::Error: Error + Send + Sync + 'static, - O: ParseHttpResponse>, +) -> Result, SdkError> +where + B: http_body::Body + Unpin, + B: From + Debug + 'static, + B::Error: Error + Send + Sync + 'static, + O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { return sdk_result(parsed_response, response); @@ -96,8 +100,8 @@ async fn load_response( let body = match read_body(response.body_mut()).await { Ok(body) => body, Err(e) => { - return Err(_SdkError::ResponseError { - raw: response, + return Err(SdkError::ResponseError { + raw: response.map(|b| Box::new(b) as _), err: Box::new(e), }); } @@ -109,18 +113,20 @@ async fn load_response( } #[derive(Clone)] -pub struct LoadResponseMiddleware { +pub struct ParseResponseService { inner: S, } +// In the future, this needs to use the CRT #[derive(Clone)] struct RetryStrategy {} impl -tower::retry::Policy, Response, Error> -for RetryStrategy where R: RetryPolicy + tower::retry::Policy, Response, Error> for RetryStrategy +where + R: RetryPolicy, { - type Future = Pin>>; + type Future = Pin>>; fn retry( &self, @@ -136,10 +142,7 @@ for RetryStrategy where R: RetryPolicy Some(Box::pin(fut)) } - fn clone_request( - &self, - req: &Operation, - ) -> Option> { + fn clone_request(&self, req: &Operation) -> Option> { let inner = req.request.try_clone()?; Some(Operation { request: inner, @@ -149,55 +152,32 @@ for RetryStrategy where R: RetryPolicy } } -/* -impl tower::Service> for RetryService where - S: Service>, - O: ParseHttpResponse + 'static, - R: RetryPolicy + Clone + 'static, - { - type Response = S::Response; - type Error = S::Error; - type Future = Pin>>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Operation) -> Self::Future { - let fut = async { - self.inner.call(req).await - }; - Box::pin(fut) - - } -}*/ - pub struct ParseResponseLayer; impl Layer for ParseResponseLayer - where - S: Service, +where + S: Service, { - type Service = LoadResponseMiddleware; + type Service = ParseResponseService; fn layer(&self, inner: S) -> Self::Service { - LoadResponseMiddleware { inner } + ParseResponseService { inner } } } -impl tower::Service> for LoadResponseMiddleware - where - S: Service, Error=OperationError>, - OE: Into, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin, - B: From, - B::Error: Error + Send + Sync + 'static, +impl tower::Service> for ParseResponseService +where + S: Service, Error = OperationError>, + OE: Into, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin + Debug + 'static, + B: From, + B::Error: Error + Send + Sync + 'static, { - type Response = _SdkSuccess; - type Error = _SdkError; - type Future = Pin>>>; + type Response = SdkSuccess; + type Error = SdkError; + type Future = Pin>>>; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx).map_err(operation_error) @@ -208,8 +188,7 @@ impl tower::Service> for LoadRe let handler = req.response_handler; let fut = async move { match resp.await { - // TODO: split variant so they we don't retry missing credentials - Err(e) => Err(operation_error::(e)), + Err(e) => Err(operation_error::(e)), Ok(resp) => load_response(resp, &handler).await, } }; @@ -217,45 +196,33 @@ impl tower::Service> for LoadRe } } -/* -impl Layer for BufferLayer -where - S: Service + Send + 'static, - S::Future: Send, - S::Error: Into + Send + Sync, - Request: Send + 'static, - - */ - impl Client - where - S: Service, Response=http::Response> +where + S: Service, Response = http::Response> + Send + Clone + 'static, - S::Error: Into + Send + Sync + 'static, - S::Future: Send + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { pub async fn call( &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { - let signer = OperationRequestMiddlewareLayer::for_middleware(SigningMiddleware::new()); - let endpoint_resolver = OperationRequestMiddlewareLayer::for_middleware(EndpointMiddleware); + let signer = OperationPipelineService::for_stage(SignRequestStage::new()); + let endpoint_resolver = OperationPipelineService::for_stage(AddEndpointStage); let inner = self.inner.clone(); // TODO: reorder to call ready_and on the entire stack /*let inner = inner .ready_and() .await .map_err(|e| _SdkError::DispatchFailure(e.into()))?;*/ - //let retry_layer = RetryLayer::new(RetryStrategy {}); let mut svc = ServiceBuilder::new() .retry(RetryStrategy {}) - //.buffer(100) .layer(ParseResponseLayer) .layer(endpoint_resolver) .layer(signer) @@ -271,14 +238,15 @@ use http_body::Body; use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; -use operation::endpoint::EndpointMiddleware; -use operation::middleware::{DispatchLayer, OperationRequestMiddlewareLayer}; -use operation::retry_policy::{RetryPolicy}; -use operation::signing_middleware::SigningMiddleware; +use operation::endpoint::AddEndpointStage; +use operation::middleware::{DispatchLayer, OperationPipelineService}; +use operation::retry_policy::RetryPolicy; +use operation::signing_middleware::SignRequestStage; +use pin_utils::core_reexport::time::Duration; +use std::fmt::Debug; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -use pin_utils::core_reexport::time::Duration; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -331,7 +299,7 @@ mod test { impl tower::Service> for TestService { type Response = http::Response; type Error = BoxError; - type Future = Pin> + Send>>; + type Future = Pin> + Send>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -348,8 +316,8 @@ mod test { struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -434,34 +402,4 @@ mod test { ); assert_eq!(request.headers().get(AUTHORIZATION).unwrap(), "AWS4-HMAC-SHA256 Credential=access/20210120/some-region/some-service/aws4_request, SignedHeaders=host, Signature=f179c6899f0a11051a11dc1bb022252b0741953663bc5ff33dfa2abfed51e0b1"); } - - /* - #[test] - fn real_service() { - let operation = Operation { - base: Request::builder() - .uri("/some_url") - .body(SdkBody::from("Hello")) - .unwrap(), - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - service: "svc".to_string(), - region: "region".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), - }, - double_uri_encode: false, - normalize_uri_path: true, - omit_session_token: false, - }), - credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), - endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - response_handler: Some(Box::new(TestOperationParser)), - }; - let client = Client::default(); - let _ = client.call(operation); - }*/ } diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operation/src/endpoint.rs index 59cc3fc0e4..c13f28214a 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operation/src/endpoint.rs @@ -92,8 +92,8 @@ impl EndpointProviderExt for Extensions { // TODO: this should probably move to a collection of middlewares #[derive(Clone, Copy)] /// Set the endpoint for a request based on the endpoint config -pub struct EndpointMiddleware; -impl OperationMiddleware for EndpointMiddleware { +pub struct AddEndpointStage; +impl OperationMiddleware for AddEndpointStage { fn apply(&self, request: crate::Request) -> Result { request.augment(|mut request, extensions| { let endpoint_provider: &Arc = extensions diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs index 53366d7397..ccff05a4e8 100644 --- a/aws/rust-runtime/operation/src/lib.rs +++ b/aws/rust-runtime/operation/src/lib.rs @@ -178,8 +178,8 @@ pub trait ParseStrictResponse { } impl ParseHttpResponse for T - where - T: ParseStrictResponse, +where + T: ParseStrictResponse, { type Output = T::Output; diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operation/src/middleware.rs index 3c1be5daec..9507ecbe62 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operation/src/middleware.rs @@ -21,17 +21,17 @@ pub struct OperationRequestMiddlewareService { middleware: M, } -pub struct OperationRequestMiddlewareLayer { +pub struct OperationPipelineService { layer: M, } -impl OperationRequestMiddlewareLayer { - pub fn for_middleware(layer: M) -> Self { - OperationRequestMiddlewareLayer { layer } +impl OperationPipelineService { + pub fn for_stage(layer: M) -> Self { + OperationPipelineService { layer } } } -impl Layer for OperationRequestMiddlewareLayer +impl Layer for OperationPipelineService where M: Clone, { @@ -173,7 +173,7 @@ where #[cfg(test)] mod test { - use crate::middleware::{DispatchLayer, OperationMiddleware, OperationRequestMiddlewareLayer}; + use crate::middleware::{DispatchLayer, OperationMiddleware, OperationPipelineService}; use crate::{ParseHttpResponse, SdkBody}; use bytes::Bytes; @@ -216,7 +216,7 @@ mod test { } } - let add_header = OperationRequestMiddlewareLayer::for_middleware(AddHeader( + let add_header = OperationPipelineService::for_stage(AddHeader( "X-Key".to_string(), "X-Value".to_string(), )); diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operation/src/signing_middleware.rs index da072c4cc8..b90fca40d4 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operation/src/signing_middleware.rs @@ -15,19 +15,19 @@ use std::time::SystemTime; use tower::BoxError; #[derive(Clone)] -pub struct SigningMiddleware { +pub struct SignRequestStage { signer: HttpSigner, } -impl Default for SigningMiddleware { +impl Default for SignRequestStage { fn default() -> Self { - SigningMiddleware::new() + SignRequestStage::new() } } -impl SigningMiddleware { +impl SignRequestStage { pub fn new() -> Self { - SigningMiddleware { + SignRequestStage { signer: HttpSigner {}, } } @@ -75,7 +75,7 @@ impl CredentialProviderExt for Extensions { } } -impl OperationMiddleware for SigningMiddleware { +impl OperationMiddleware for SignRequestStage { fn apply(&self, request: crate::Request) -> Result { request.augment(|request, config| { let operation_config = config.signing_config().ok_or("Missing signing config")?; diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 951a00fd52..ec13d22dd3 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -5,6 +5,7 @@ use std::error::Error; +use aws_hyper::{SdkError, SdkSuccess}; use dynamodb::error::ListTablesError; use dynamodb::output::ListTablesOutput; use dynamodb::{ @@ -17,15 +18,18 @@ use env_logger::Env; use operation::endpoint::StaticEndpoint; use operation::retry_policy::{RetryPolicy, RetryType}; use tokio::time::Duration; -use aws_hyper::{_SdkSuccess, _SdkError}; #[derive(Clone)] struct RetryIfNoTables; -impl RetryPolicy<_SdkSuccess, _SdkError> for RetryIfNoTables { - fn should_retry(&self, input: Result<&_SdkSuccess, &_SdkError>) -> Option { +impl RetryPolicy, SdkError> for RetryIfNoTables { + fn should_retry( + &self, + input: Result<&SdkSuccess, &SdkError>, + ) -> Option { match input { Ok(list_tables) => { - if list_tables.parsed + if list_tables + .parsed .table_names .as_ref() .map(|t| t.len()) @@ -58,10 +62,9 @@ async fn main() -> Result<(), Box> { ))) .build(); let client = aws_hyper::Client::default().with_tracing(); - let list_tables = dynamodb::operation::ListTables::builder() - .build(&config); - // For a custom retry policy: - // .with_policy(RetryIfNoTables); + let list_tables = dynamodb::operation::ListTables::builder().build(&config); + // For a custom retry policy: + // .with_policy(RetryIfNoTables); let response = client.call(list_tables).await; let tables = match response { From 9decb96e73392769d80493d78f4fb479fbe36168 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 25 Jan 2021 09:48:07 -0500 Subject: [PATCH 33/50] aws-hyper building again --- aws/rust-runtime/aws-hyper/Cargo.toml | 3 +- aws/rust-runtime/aws-hyper/src/lib.rs | 89 +++----- aws/rust-runtime/operation/src/extensions.rs | 187 ----------------- aws/rust-runtime/operation/src/lib.rs | 193 ------------------ .../{operation => operationwip}/Cargo.toml | 3 +- .../src/endpoint.rs | 17 +- aws/rust-runtime/operationwip/src/lib.rs | 6 + .../src/middleware.rs | 25 +-- .../{operation => operationwip}/src/region.rs | 4 +- .../src/retry_policy.rs | 0 .../src/signing_middleware.rs | 11 +- rust-runtime/smithy-http/src/operation.rs | 23 ++- 12 files changed, 93 insertions(+), 468 deletions(-) delete mode 100644 aws/rust-runtime/operation/src/extensions.rs delete mode 100644 aws/rust-runtime/operation/src/lib.rs rename aws/rust-runtime/{operation => operationwip}/Cargo.toml (83%) rename aws/rust-runtime/{operation => operationwip}/src/endpoint.rs (89%) create mode 100644 aws/rust-runtime/operationwip/src/lib.rs rename aws/rust-runtime/{operation => operationwip}/src/middleware.rs (90%) rename aws/rust-runtime/{operation => operationwip}/src/region.rs (95%) rename aws/rust-runtime/{operation => operationwip}/src/retry_policy.rs (100%) rename aws/rust-runtime/{operation => operationwip}/src/signing_middleware.rs (93%) diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 46e24aecdf..7775b0baf9 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] hyper = { version = "0.14.2", features = ["client", "http1", "http2"] } tower = { version = "0.4.2", features = ["retry", "buffer"] } -operation = { path = "../operation" } +operationwip = { path = "../operationwip" } middleware-tracing = { path = "../middleware-tracing" } hyper-tls = "0.5.0" auth = { path = "../auth" } @@ -17,6 +17,7 @@ http = "0.2.3" bytes = "1" http-body = "0.4.0" tokio = { version = "1", features = ["time"]} +smithy-http = { path = "../../../rust-runtime/smithy-http" } pin-utils = "0.1.0" [dev-dependencies] diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 7813b5f8d0..7bf2658f19 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,6 +1,9 @@ use bytes::{Buf, Bytes}; use hyper::Client as HyperClient; -use operation::{middleware::OperationError, Operation, ParseHttpResponse, SdkBody}; +use operationwip::middleware::OperationError; +use smithy_http::body::SdkBody; +use smithy_http::operation; +use smithy_http::response::ParseHttpResponse; use std::error::Error; use tower::{Layer, Service, ServiceBuilder}; @@ -133,7 +136,7 @@ where req: &Operation, result: Result<&Response, &Error>, ) -> Option { - let _resp = req.retry_policy.should_retry(result)?; + let _resp = req.retry_policy().should_retry(result)?; let next = self.clone(); let fut = async move { tokio::time::sleep(Duration::new(5, 0)).await; @@ -143,12 +146,7 @@ where } fn clone_request(&self, req: &Operation) -> Option> { - let inner = req.request.try_clone()?; - Some(Operation { - request: inner, - response_handler: req.response_handler.clone(), - retry_policy: req.retry_policy.clone(), - }) + req.try_clone() } } @@ -184,8 +182,8 @@ where } fn call(&mut self, req: Operation) -> Self::Future { - let resp = self.inner.call(req.request); - let handler = req.response_handler; + let (req, handler) = req.into_request_response(); + let resp = self.inner.call(req); let fut = async move { match resp.await { Err(e) => Err(operation_error::(e)), @@ -238,15 +236,16 @@ use http_body::Body; use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; -use operation::endpoint::AddEndpointStage; -use operation::middleware::{DispatchLayer, OperationPipelineService}; -use operation::retry_policy::RetryPolicy; -use operation::signing_middleware::SignRequestStage; -use pin_utils::core_reexport::time::Duration; +use operationwip::endpoint::AddEndpointStage; +use operationwip::middleware::{DispatchLayer, OperationPipelineService}; +use operationwip::retry_policy::RetryPolicy; +use operationwip::signing_middleware::SignRequestStage; use std::fmt::Debug; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; +use smithy_http::operation::Operation; +use std::time::Duration; async fn read_body(body: B) -> Result, B::Error> { let mut output = Vec::new(); @@ -268,18 +267,21 @@ mod test { use bytes::Bytes; use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; - use operation::endpoint::StaticEndpoint; - use operation::region::Region; - use operation::signing_middleware::SigningConfigExt; - use operation::{Operation, ParseHttpResponse, SdkBody}; + use operationwip::endpoint::{StaticEndpoint, EndpointProviderExt}; + use operationwip::region::Region; + use operationwip::signing_middleware::SigningConfigExt; + use smithy_http::operation::Operation; use pin_utils::core_reexport::task::{Context, Poll}; - use pin_utils::core_reexport::time::Duration; + use std::time::Duration; use std::error::Error; use std::fmt::Formatter; use std::future::Future; use std::pin::Pin; use std::sync::{mpsc, Arc}; use std::time::UNIX_EPOCH; + use smithy_http::body::SdkBody; + use smithy_http::response::ParseHttpResponse; + use smithy_http::operation; #[derive(Clone)] struct TestService { @@ -347,44 +349,19 @@ mod test { .uri("/some_url") .body(SdkBody::from("Hello")) .unwrap(), - ); - - request - .config - .lock() - .unwrap() - .insert(Region::new("some-region")); - request - .config - .lock() - .unwrap() - .insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - - request - .config - .lock() - .unwrap() - .insert_signing_config(auth::OperationSigningConfig::default_config("some-service")); - use operation::signing_middleware::CredentialProviderExt; - request - .config - .lock() - .unwrap() - .insert_credentials_provider(Arc::new(Credentials::from_static("access", "secret"))); - - use operation::endpoint::EndpointProviderExt; - request - .config - .lock() - .unwrap() - .insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + ).augment(|req, config| { + config.insert(Region::new("some-region")); + config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); + config.insert_signing_config(auth::OperationSigningConfig::default_config("some-service")); + use operationwip::signing_middleware::CredentialProviderExt; + config.insert_credentials_provider(Arc::new(Credentials::from_static("access", "secret"))); + config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( "http://localhost:8000", )))); - let operation = Operation { - request, - response_handler: TestOperationParser, - retry_policy: (), - }; + Result::<_, ()>::Ok(req) + }).expect("valid request"); + + let operation = Operation::new(request, TestOperationParser); let (svc, rx) = TestService::new(|_req| http::Response::new(hyper::Body::from("hello!"))); let client = Client { inner: svc }; diff --git a/aws/rust-runtime/operation/src/extensions.rs b/aws/rust-runtime/operation/src/extensions.rs deleted file mode 100644 index 6d398c27ab..0000000000 --- a/aws/rust-runtime/operation/src/extensions.rs +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -// Adapted from Hyper Extensions -use std::any::{Any, TypeId}; -use std::collections::HashMap; -use std::fmt; -use std::hash::{BuildHasherDefault, Hasher}; - -type AnyMap = HashMap, BuildHasherDefault>; - -// With TypeIds as keys, there's no need to hash them. They are already hashes -// themselves, coming from the compiler. The IdHasher just holds the u64 of -// the TypeId, and then returns it, instead of doing any bit fiddling. -#[derive(Default)] -struct IdHasher(u64); - -impl Hasher for IdHasher { - #[inline] - fn finish(&self) -> u64 { - self.0 - } - - fn write(&mut self, _: &[u8]) { - unreachable!("TypeId calls write_u64"); - } - - #[inline] - fn write_u64(&mut self, id: u64) { - self.0 = id; - } -} - -/// A type map of protocol extensions. -/// -/// `Extensions` can be used by `Request` and `Response` to store -/// extra data derived from the underlying protocol. -#[derive(Default)] -pub struct Extensions { - // If extensions are never used, no need to carry around an empty HashMap. - // That's 3 words. Instead, this is only 1 word. - map: Option>, -} - -impl Extensions { - /// Create an empty `Extensions`. - #[inline] - pub fn new() -> Extensions { - Extensions { map: None } - } - - /// Insert a type into this `Extensions`. - /// - /// If a extension of this type already existed, it will - /// be returned. - /// - /// # Example - /// - /// ``` - /// # use http::Extensions; - /// let mut ext = Extensions::new(); - /// assert!(ext.insert(5i32).is_none()); - /// assert!(ext.insert(4u8).is_none()); - /// assert_eq!(ext.insert(9i32), Some(5i32)); - /// ``` - pub fn insert(&mut self, val: T) -> Option { - self.map - .get_or_insert_with(|| Box::new(HashMap::default())) - .insert(TypeId::of::(), Box::new(val)) - .and_then(|boxed| { - (boxed as Box) - .downcast() - .ok() - .map(|boxed| *boxed) - }) - } - - /// Get a reference to a type previously inserted on this `Extensions`. - /// - /// # Example - /// - /// ``` - /// # use http::Extensions; - /// let mut ext = Extensions::new(); - /// assert!(ext.get::().is_none()); - /// ext.insert(5i32); - /// - /// assert_eq!(ext.get::(), Some(&5i32)); - /// ``` - pub fn get(&self) -> Option<&T> { - self.map - .as_ref() - .and_then(|map| map.get(&TypeId::of::())) - .and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref()) - } - - /// Get a mutable reference to a type previously inserted on this `Extensions`. - /// - /// # Example - /// - /// ``` - /// # use http::Extensions; - /// let mut ext = Extensions::new(); - /// ext.insert(String::from("Hello")); - /// ext.get_mut::().unwrap().push_str(" World"); - /// - /// assert_eq!(ext.get::().unwrap(), "Hello World"); - /// ``` - pub fn get_mut(&mut self) -> Option<&mut T> { - self.map - .as_mut() - .and_then(|map| map.get_mut(&TypeId::of::())) - .and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut()) - } - - /// Remove a type from this `Extensions`. - /// - /// If a extension of this type existed, it will be returned. - /// - /// # Example - /// - /// ``` - /// # use http::Extensions; - /// let mut ext = Extensions::new(); - /// ext.insert(5i32); - /// assert_eq!(ext.remove::(), Some(5i32)); - /// assert!(ext.get::().is_none()); - /// ``` - pub fn remove(&mut self) -> Option { - self.map - .as_mut() - .and_then(|map| map.remove(&TypeId::of::())) - .and_then(|boxed| { - (boxed as Box) - .downcast() - .ok() - .map(|boxed| *boxed) - }) - } - - /// Clear the `Extensions` of all inserted extensions. - /// - /// # Example - /// - /// ``` - /// # use http::Extensions; - /// let mut ext = Extensions::new(); - /// ext.insert(5i32); - /// ext.clear(); - /// - /// assert!(ext.get::().is_none()); - /// ``` - #[inline] - pub fn clear(&mut self) { - if let Some(ref mut map) = self.map { - map.clear(); - } - } -} - -impl fmt::Debug for Extensions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Extensions").finish() - } -} - -#[test] -fn test_extensions() { - #[derive(Debug, PartialEq)] - struct MyType(i32); - - let mut extensions = Extensions::new(); - - extensions.insert(5i32); - extensions.insert(MyType(10)); - - assert_eq!(extensions.get(), Some(&5i32)); - assert_eq!(extensions.get_mut(), Some(&mut 5i32)); - - assert_eq!(extensions.remove::(), Some(5i32)); - assert!(extensions.get::().is_none()); - - assert_eq!(extensions.get::(), None); - assert_eq!(extensions.get(), Some(&MyType(10))); -} diff --git a/aws/rust-runtime/operation/src/lib.rs b/aws/rust-runtime/operation/src/lib.rs deleted file mode 100644 index ccff05a4e8..0000000000 --- a/aws/rust-runtime/operation/src/lib.rs +++ /dev/null @@ -1,193 +0,0 @@ -use bytes::Bytes; - -pub mod endpoint; -mod extensions; -pub mod middleware; -pub mod region; -pub mod retry_policy; -pub mod signing_middleware; - -use crate::extensions::Extensions; -use http::{HeaderMap, HeaderValue, Response}; -use std::error::Error; -use std::pin::Pin; -use std::sync::{Arc, Mutex}; -use std::task::{Context, Poll}; - -type BodyError = Box; - -#[derive(Debug)] -pub enum SdkBody { - Once(Option), -} - -impl http_body::Body for SdkBody { - type Data = Bytes; - type Error = BodyError; - - fn poll_data( - mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll>> { - self.poll_inner() - } - - fn poll_trailers( - self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll>, Self::Error>> { - Poll::Ready(Ok(None)) - } -} - -impl SdkBody { - fn poll_inner(&mut self) -> Poll>> { - match self { - SdkBody::Once(ref mut opt) => { - let data = opt.take(); - match data { - Some(bytes) => Poll::Ready(Some(Ok(bytes))), - None => Poll::Ready(None), - } - } - } - } - - /// If possible, return a reference to this body as `&[u8]` - /// - /// If this SdkBody is NOT streaming, this will return the byte slab - /// If this SdkBody is streaming, this will return `None` - pub fn bytes(&self) -> Option<&[u8]> { - match self { - SdkBody::Once(Some(b)) => Some(&b), - SdkBody::Once(None) => Some(&[]), - // In the future, streaming variants will return `None` - } - } - - pub fn try_clone(&self) -> Option { - match self { - SdkBody::Once(bytes) => Some(SdkBody::Once(bytes.clone())), - } - } -} - -impl From<&str> for SdkBody { - fn from(s: &str) -> Self { - SdkBody::Once(Some(Bytes::copy_from_slice(s.as_bytes()))) - } -} - -impl From for SdkBody { - fn from(bytes: Bytes) -> Self { - SdkBody::Once(Some(bytes)) - } -} - -impl From> for SdkBody { - fn from(data: Vec) -> SdkBody { - Self::from(Bytes::from(data)) - } -} - -// TODO: consider field privacy, builders, etc. -pub struct Operation { - pub request: Request, - pub response_handler: H, - pub retry_policy: R, -} - -impl Operation { - pub fn new(request: Request, response_handler: H) -> Self { - Operation { - request, - response_handler, - retry_policy: (), - } - } - - pub fn with_policy(self, retry_policy: R) -> Operation { - Operation { - request: self.request, - response_handler: self.response_handler, - retry_policy, - } - } -} - -pub struct Request { - pub base: http::Request, - pub config: Arc>, -} - -impl Request { - pub fn new(base: http::Request) -> Self { - Request { - base, - config: Arc::new(Mutex::new(Extensions::new())), - } - } - - pub fn augment( - self, - f: impl FnOnce(http::Request, &mut Extensions) -> Result, T>, - ) -> Result { - let base = { - let mut extensions = (&self.config).lock().unwrap(); - f(self.base, &mut extensions)? - }; - Ok(Request { - base, - config: self.config, - }) - } - - pub fn try_clone(&self) -> Option { - let cloned_body = self.base.body().try_clone()?; - let mut cloned_request = http::Request::builder() - .uri(self.base.uri().clone()) - .method(self.base.method()); - for (name, value) in self.base.headers() { - cloned_request = cloned_request.header(name, value) - } - let base = cloned_request - .body(cloned_body) - .expect("should be clonable"); - Some(Request { - base, - config: self.config.clone(), - }) - } -} - -pub trait ParseHttpResponse { - type Output; - /// Parse an HTTP request without reading the body. If the body must be provided to proceed, - /// return `None` - /// - /// This exists to serve APIs like S3::GetObject where the body is passed directly into the - /// response and consumed by the client. However, even in the case of S3::GetObject, errors - /// require reading the entire body. - fn parse_unloaded(&self, response: &mut http::Response) -> Option; - fn parse_loaded(&self, response: &http::Response) -> Self::Output; -} - -pub trait ParseStrictResponse { - type Output; - fn parse(&self, response: &Response) -> Self::Output; -} - -impl ParseHttpResponse for T -where - T: ParseStrictResponse, -{ - type Output = T::Output; - - fn parse_unloaded(&self, _response: &mut Response) -> Option { - None - } - - fn parse_loaded(&self, response: &Response) -> Self::Output { - self.parse(response) - } -} diff --git a/aws/rust-runtime/operation/Cargo.toml b/aws/rust-runtime/operationwip/Cargo.toml similarity index 83% rename from aws/rust-runtime/operation/Cargo.toml rename to aws/rust-runtime/operationwip/Cargo.toml index aee0828625..978d7893e2 100644 --- a/aws/rust-runtime/operation/Cargo.toml +++ b/aws/rust-runtime/operationwip/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "operation" +name = "operationwip" version = "0.1.0" authors = ["Russell Cohen "] edition = "2018" @@ -13,6 +13,7 @@ bytes = "1" tower = { version = "0.4.2", features = ["util"] } http-body = "0.4.0" pin-project = "1.0.4" +smithy-http = { path = "../../../rust-runtime/smithy-http"} [dev-dependencies] tokio = { version = "1", features = ["full"] } diff --git a/aws/rust-runtime/operation/src/endpoint.rs b/aws/rust-runtime/operationwip/src/endpoint.rs similarity index 89% rename from aws/rust-runtime/operation/src/endpoint.rs rename to aws/rust-runtime/operationwip/src/endpoint.rs index c13f28214a..5db3c97ad0 100644 --- a/aws/rust-runtime/operation/src/endpoint.rs +++ b/aws/rust-runtime/operationwip/src/endpoint.rs @@ -8,11 +8,12 @@ use std::str::FromStr; use http::uri::Uri; -use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; use http::header::HOST; use std::sync::Arc; use tower::BoxError; +use smithy_http::operation; +use smithy_http::property_bag::PropertyBag; pub struct StaticEndpoint(http::Uri); @@ -58,15 +59,17 @@ impl ProvideEndpoint for StaticEndpoint { } } +/* impl OperationMiddleware for T where T: ProvideEndpoint, { - fn apply(&self, mut request: crate::Request) -> Result { - self.set_endpoint(&mut request.base.uri_mut()); - Ok(request) + fn apply(&self, mut request: operation::Request) -> Result { + request.augment(|request, config| { + self.set_endpoint(&mut request.); + }) } -} +}*/ pub trait EndpointProviderExt { fn endpoint_provider(&self) -> Option<&Arc>; @@ -76,7 +79,7 @@ pub trait EndpointProviderExt { ) -> Option>; } -impl EndpointProviderExt for Extensions { +impl EndpointProviderExt for PropertyBag { fn endpoint_provider(&self) -> Option<&Arc> { self.get() } @@ -94,7 +97,7 @@ impl EndpointProviderExt for Extensions { /// Set the endpoint for a request based on the endpoint config pub struct AddEndpointStage; impl OperationMiddleware for AddEndpointStage { - fn apply(&self, request: crate::Request) -> Result { + fn apply(&self, request: operation::Request) -> Result { request.augment(|mut request, extensions| { let endpoint_provider: &Arc = extensions .endpoint_provider() diff --git a/aws/rust-runtime/operationwip/src/lib.rs b/aws/rust-runtime/operationwip/src/lib.rs new file mode 100644 index 0000000000..2b613ef8bf --- /dev/null +++ b/aws/rust-runtime/operationwip/src/lib.rs @@ -0,0 +1,6 @@ + +pub mod endpoint; +pub mod middleware; +pub mod region; +pub mod retry_policy; +pub mod signing_middleware; diff --git a/aws/rust-runtime/operation/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs similarity index 90% rename from aws/rust-runtime/operation/src/middleware.rs rename to aws/rust-runtime/operationwip/src/middleware.rs index 9507ecbe62..46ca5d5d37 100644 --- a/aws/rust-runtime/operation/src/middleware.rs +++ b/aws/rust-runtime/operationwip/src/middleware.rs @@ -3,16 +3,18 @@ * SPDX-License-Identifier: Apache-2.0. */ -use crate::SdkBody; use std::error::Error; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use tower::{Layer, Service}; type BoxError = Box; +use pin_project::pin_project; +use smithy_http::body::SdkBody; +use smithy_http::operation; pub trait OperationMiddleware { - fn apply(&self, request: crate::Request) -> Result; + fn apply(&self, request: operation::Request) -> Result; } #[derive(Clone)] @@ -69,9 +71,9 @@ where } } -impl Service for OperationRequestMiddlewareService +impl Service for OperationRequestMiddlewareService where - S: Service, + S: Service, M: OperationMiddleware, S::Error: RequestConstructionErr, { @@ -83,7 +85,7 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, req: crate::Request) -> Self::Future { + fn call(&mut self, req: operation::Request) -> Self::Future { match self .middleware .apply(req) @@ -130,8 +132,6 @@ impl RequestConstructionErr for OperationError { } } -use pin_project::pin_project; - #[pin_project] pub struct OperationFuture { #[pin] @@ -150,7 +150,7 @@ where } } -impl Service for DispatchMiddleware +impl Service for DispatchMiddleware where S: Service>, { @@ -164,9 +164,10 @@ where .map_err(OperationError::DispatchError) } - fn call(&mut self, req: crate::Request) -> Self::Future { + fn call(&mut self, req: operation::Request) -> Self::Future { + let (req, _propery_bag) = req.into_parts(); OperationFuture { - f: self.inner.call(req.base), + f: self.inner.call(req), } } } @@ -207,7 +208,7 @@ mod test { #[derive(Clone)] struct AddHeader(String, String); impl OperationMiddleware for AddHeader { - fn apply(&self, mut request: crate::Request) -> Result> { + fn apply(&self, mut request: operation::Request) -> Result> { request.base.headers_mut().append( HeaderName::from_str(&self.0).unwrap(), HeaderValue::from_str(&self.0).unwrap(), @@ -234,7 +235,7 @@ mod test { } }); let mut service = add_header.layer(DispatchLayer.layer(http_service)); - let operation = crate::Request::new( + let operation = operation::Request::new( Request::builder() .uri("/some_url") .body(SdkBody::from("Hello")) diff --git a/aws/rust-runtime/operation/src/region.rs b/aws/rust-runtime/operationwip/src/region.rs similarity index 95% rename from aws/rust-runtime/operation/src/region.rs rename to aws/rust-runtime/operationwip/src/region.rs index 08b2ec9cde..06db427ac6 100644 --- a/aws/rust-runtime/operation/src/region.rs +++ b/aws/rust-runtime/operationwip/src/region.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0. */ -use crate::extensions::Extensions; +use smithy_http::property_bag::PropertyBag; #[derive(Clone)] pub struct Region(String); @@ -54,7 +54,7 @@ pub trait RegionExt { fn signing_region(&self) -> Option<&str>; } -impl RegionExt for Extensions { +impl RegionExt for PropertyBag { fn request_region(&self) -> Option<&str> { self.get::().map(|reg| reg.0.as_str()) } diff --git a/aws/rust-runtime/operation/src/retry_policy.rs b/aws/rust-runtime/operationwip/src/retry_policy.rs similarity index 100% rename from aws/rust-runtime/operation/src/retry_policy.rs rename to aws/rust-runtime/operationwip/src/retry_policy.rs diff --git a/aws/rust-runtime/operation/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs similarity index 93% rename from aws/rust-runtime/operation/src/signing_middleware.rs rename to aws/rust-runtime/operationwip/src/signing_middleware.rs index b90fca40d4..f60c59f66d 100644 --- a/aws/rust-runtime/operation/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -2,9 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ -use crate::extensions::Extensions; use crate::middleware::OperationMiddleware; -use crate::region::RegionExt; use auth::{ HttpSigner, HttpSigningConfig, OperationSigningConfig, ProvideCredentials, RequestConfig, SigningConfig, @@ -13,6 +11,9 @@ use http::Request; use std::sync::Arc; use std::time::SystemTime; use tower::BoxError; +use smithy_http::operation; +use smithy_http::property_bag::PropertyBag; +use crate::region::RegionExt; #[derive(Clone)] pub struct SignRequestStage { @@ -41,7 +42,7 @@ pub trait SigningConfigExt { ) -> Option; } -impl SigningConfigExt for Extensions { +impl SigningConfigExt for PropertyBag { fn signing_config(&self) -> Option<&OperationSigningConfig> { self.get() } @@ -62,7 +63,7 @@ pub trait CredentialProviderExt { ) -> Option>; } -impl CredentialProviderExt for Extensions { +impl CredentialProviderExt for PropertyBag { fn credentials_provider(&self) -> Option<&Arc> { self.get() } @@ -76,7 +77,7 @@ impl CredentialProviderExt for Extensions { } impl OperationMiddleware for SignRequestStage { - fn apply(&self, request: crate::Request) -> Result { + fn apply(&self, request: operation::Request) -> Result { request.augment(|request, config| { let operation_config = config.signing_config().ok_or("Missing signing config")?; let cred_provider = config diff --git a/rust-runtime/smithy-http/src/operation.rs b/rust-runtime/smithy-http/src/operation.rs index 2df4e5cb4f..d4586c49f4 100644 --- a/rust-runtime/smithy-http/src/operation.rs +++ b/rust-runtime/smithy-http/src/operation.rs @@ -10,10 +10,6 @@ pub struct Operation { } impl Operation { - pub fn into_request_response(self) -> (Request, H) { - (self.request, self.response_handler) - } - pub fn new(request: Request, response_handler: H) -> Self { Operation { request, @@ -23,6 +19,25 @@ impl Operation { } } +impl Operation { + pub fn try_clone(&self) -> Option where H: Clone, R: Clone { + let inner = self.request.try_clone()?; + Some(Operation { + request: inner, + response_handler: self.response_handler.clone(), + _retry_policy: self._retry_policy.clone(), + }) + } + + pub fn into_request_response(self) -> (Request, H) { + (self.request, self.response_handler) + } + + pub fn retry_policy(&self) -> &R { + &self._retry_policy + } +} + pub struct Request { /// The underlying HTTP Request inner: http::Request, From 2c6d2c652d89be329e49d130f9d79ad2dc94e2f5 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 25 Jan 2021 10:24:51 -0500 Subject: [PATCH 34/50] Tests passing again --- .../smithy/rustsdk/AwsCodegenDecorator.kt | 2 +- .../amazon/smithy/rustsdk/EndpointConfig.kt | 8 ++++---- .../amazon/smithy/rustsdk/RegionConfig.kt | 19 ++++++++++--------- .../amazon/smithy/rustsdk/SigningConfig.kt | 8 ++++---- aws/sdk/build.gradle.kts | 4 +++- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 13 +++++++++---- aws/sdk/examples/dynamo-helloworld/Cargo.toml | 2 +- .../examples/dynamo-helloworld/src/main.rs | 4 ++-- .../rust/codegen/rustlang/CargoDependency.kt | 4 +++- .../rust/codegen/smithy/RuntimeTypes.kt | 6 ++++-- .../smithy/generators/BuilderGenerator.kt | 9 ++++++--- rust-runtime/smithy-http/src/body.rs | 1 + rust-runtime/smithy-http/src/operation.rs | 8 ++++++++ 13 files changed, 56 insertions(+), 32 deletions(-) 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 002161664d..6a248aff5c 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 @@ -21,7 +21,7 @@ class AwsCodegenDecorator : RustCodegenDecorator { ): List { val awsCustomizations = mutableListOf() awsCustomizations += CredentialProviderConfig() - awsCustomizations += RegionConfig() + awsCustomizations += RegionConfig(protocolConfig.runtimeConfig) awsCustomizations += EndpointConfigCustomization(protocolConfig) protocolConfig.serviceShape.getTrait(SigV4Trait::class.java).map { trait -> awsCustomizations += SigV4SigningConfig(trait) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt index 00f3c79fc2..353e63bd93 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt @@ -52,8 +52,8 @@ class EndpointConfigCustomization(private val protocolConfig: ProtocolConfig) : } } -fun EndpointProvider(runtimeConfig: RuntimeConfig) = RuntimeType("ProvideEndpoint", CargoDependency.Operation(runtimeConfig), "operation::endpoint") -fun StaticEndpoint(runtimeConfig: RuntimeConfig) = RuntimeType("StaticEndpoint", CargoDependency.Operation(runtimeConfig), "operation::endpoint") +fun EndpointProvider(runtimeConfig: RuntimeConfig) = RuntimeType("ProvideEndpoint", CargoDependency.OperationWip(runtimeConfig), "operationwip::endpoint") +fun StaticEndpoint(runtimeConfig: RuntimeConfig) = RuntimeType("StaticEndpoint", CargoDependency.OperationWip(runtimeConfig), "operationwip::endpoint") class EndpointConfigPlugin(private val operationShape: OperationShape) : OperationCustomization() { override fun section(section: OperationSection): Writable { @@ -65,8 +65,8 @@ class EndpointConfigPlugin(private val operationShape: OperationShape) : Operati OperationSection.Plugin -> writable { rust( """ - use operation::endpoint::EndpointProviderExt; - request.config.lock().unwrap().insert_endpoint_provider(_config.endpoint_provider.clone()); + use operationwip::endpoint::EndpointProviderExt; + request.config_mut().insert_endpoint_provider(_config.endpoint_provider.clone()); """ ) } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt index d5016b8b08..94b431ef6b 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt @@ -7,23 +7,24 @@ package software.amazon.smithy.rustsdk import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.rustlang.Local import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.smithy.generators.OperationSection import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig -class RegionConfig : ConfigCustomization() { +class RegionConfig(runtimeConfig: RuntimeConfig) : ConfigCustomization() { + private val region = Region(runtimeConfig) override fun section(section: ServiceConfig) = writable { when (section) { - is ServiceConfig.ConfigStruct -> rust("pub region: Option<#T::Region>,", Region) + is ServiceConfig.ConfigStruct -> rust("pub region: Option<#T::Region>,", region) is ServiceConfig.ConfigImpl -> emptySection is ServiceConfig.BuilderStruct -> - rust("region: Option<#T::Region>,", Region) + rust("region: Option<#T::Region>,", region) ServiceConfig.BuilderImpl -> rust( """ @@ -32,14 +33,14 @@ class RegionConfig : ConfigCustomization() { self } """, - Region + region ) ServiceConfig.BuilderPreamble -> rust( """ use #1T::ProvideRegion; let region = self.region.or_else(||#1T::default_provider().region()); """, - Region + region ) ServiceConfig.BuilderBuild -> rust( """region: region.clone(),""", @@ -56,7 +57,7 @@ class RegionConfigPlugin(private val operationShape: OperationShape) : Operation rust( """ if let Some(region) = &_config.region { - request.config.lock().unwrap().insert(region.clone()); + request.config_mut().insert(region.clone()); } """ @@ -66,5 +67,5 @@ class RegionConfigPlugin(private val operationShape: OperationShape) : Operation } } -val Operation = CargoDependency("operation", Local("../")) -val Region = RuntimeType("region", Operation, "operation") +fun Region(runtimeConfig: RuntimeConfig) = + RuntimeType("region", CargoDependency.OperationWip(runtimeConfig), "operationwip") diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt index 34cc81a16f..695859a304 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt @@ -40,12 +40,12 @@ class SigV4SigningPlugin(operationShape: OperationShape) : OperationCustomizatio is OperationSection.Plugin -> writable { rust( """ - use operation::signing_middleware::SigningConfigExt; - request.config.lock().unwrap().insert_signing_config( + use operationwip::signing_middleware::SigningConfigExt; + request.config_mut().insert_signing_config( auth::OperationSigningConfig::default_config(_config.signing_service()) ); - use operation::signing_middleware::CredentialProviderExt; - request.config.lock().unwrap().insert_credentials_provider(_config.credentials_provider.clone()); + use operationwip::signing_middleware::CredentialProviderExt; + request.config_mut().insert_credentials_provider(_config.credentials_provider.clone()); """ ) } diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index f448d13771..250e8700d9 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -23,7 +23,7 @@ val awsServices = discoverServices() // TODO: smithy-http should be removed val runtimeModules = listOf("smithy-types", "smithy-http") val examples = listOf("dynamo-helloworld") -val awsModules = listOf("auth", "operation", "aws-hyper", "middleware-tracing") +val awsModules = listOf("auth", "operationwip", "aws-hyper", "middleware-tracing") buildscript { val smithyVersion: String by project @@ -137,7 +137,9 @@ tasks.register("relocateAwsRuntime") { } exclude("**/target") exclude("**/Cargo.lock") + filter { line -> line.replace("../../rust-runtime/", "") } into(sdkOutputDir) + outputs.upToDateWhen { false } } fun generateCargoWorkspace(services: List): String { diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index a3f474cd82..101f0c1f8b 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -45,8 +45,9 @@ dependencies = [ "hyper", "hyper-tls", "middleware-tracing", - "operation", + "operationwip", "pin-utils", + "smithy-http", "tokio", "tower", ] @@ -139,7 +140,7 @@ dependencies = [ "dynamodb", "env_logger", "http", - "operation", + "operationwip", "tokio", ] @@ -150,7 +151,7 @@ dependencies = [ "auth", "bytes", "http", - "operation", + "operationwip", "rand 0.7.3", "serde", "serde_json", @@ -585,7 +586,7 @@ dependencies = [ ] [[package]] -name = "operation" +name = "operationwip" version = "0.1.0" dependencies = [ "auth", @@ -593,6 +594,7 @@ dependencies = [ "http", "http-body", "pin-project 1.0.4", + "smithy-http", "tower", ] @@ -960,6 +962,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" name = "smithy-http" version = "0.0.1" dependencies = [ + "bytes", + "http", + "http-body", "smithy-types", ] diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.toml b/aws/sdk/examples/dynamo-helloworld/Cargo.toml index 6240cb1e0a..855746a4e6 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.toml +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] dynamodb = { version = "0.0.1", path = "../../build/aws-sdk/dynamodb" } aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } -operation = { path = "../../build/aws-sdk/operation" } +operationwip = { path = "../../build/aws-sdk/operationwip" } auth = { path = "../../build/aws-sdk/auth" } tokio = { version = "1", features = ["full"] } http = "0.2.3" diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 6844b8e9e4..8d5d1f6d1c 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -15,8 +15,8 @@ use dynamodb::{ operation::CreateTable, }; use env_logger::Env; -use operation::endpoint::StaticEndpoint; -use operation::retry_policy::{RetryPolicy, RetryType}; +use operationwip::endpoint::StaticEndpoint; +use operationwip::retry_policy::{RetryPolicy, RetryType}; use tokio::time::Duration; #[derive(Clone)] diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt index 8cb97d3fd6..43f9acb481 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt @@ -152,7 +152,9 @@ data class CargoDependency( val Bytes: RustDependency = CargoDependency("bytes", CratesIo("1")) val Rand: CargoDependency = CargoDependency("rand", CratesIo("0.7")) val Http: CargoDependency = CargoDependency("http", CratesIo("0.2")) - fun Operation(runtimeConfig: RuntimeConfig): CargoDependency = CargoDependency("operation", Local(runtimeConfig.relativePath)) + // WIP being refactored + fun OperationWip(runtimeConfig: RuntimeConfig): CargoDependency = CargoDependency("operationwip", Local(runtimeConfig.relativePath)) + fun SmithyTypes(runtimeConfig: RuntimeConfig) = CargoDependency("${runtimeConfig.cratePrefix}-types", Local(runtimeConfig.relativePath)) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt index fff0fb68cc..3a1b54883f 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RuntimeTypes.kt @@ -143,7 +143,8 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n val Config = RuntimeType("config", null, "crate") - fun Operation(runtimeConfig: RuntimeConfig) = RuntimeType("Operation", dependency = CargoDependency.Operation(runtimeConfig), namespace = "operation") + fun Operation(runtimeConfig: RuntimeConfig) = RuntimeType("Operation", dependency = CargoDependency.SmithyHttp(runtimeConfig), namespace = "smithy_http::operation") + fun OperationModule(runtimeConfig: RuntimeConfig) = RuntimeType(null, dependency = CargoDependency.SmithyHttp(runtimeConfig), namespace = "smithy_http::operation") fun BlobSerde(runtimeConfig: RuntimeConfig) = RuntimeType("blob_serde", InlineDependency.blobSerde(runtimeConfig), "crate") @@ -153,6 +154,7 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n namespace = "crate::$module" ) - fun ParseStrict(runtimeConfig: RuntimeConfig): RuntimeType = RuntimeType("ParseStrictResponse", dependency = CargoDependency.Operation(runtimeConfig), namespace = "operation") + fun ParseStrict(runtimeConfig: RuntimeConfig): RuntimeType = RuntimeType("ParseStrictResponse", dependency = CargoDependency.SmithyHttp(runtimeConfig), namespace = "smithy_http::response") + fun SdkBody(runtimeConfig: RuntimeConfig): RuntimeType = RuntimeType("SdkBody", dependency = CargoDependency.SmithyHttp(runtimeConfig), "smithy_http::body") } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index 73eada50ba..0917981735 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -65,6 +65,8 @@ class OperationInputBuilderGenerator( private val shape: OperationShape, private val plugins: List = listOf() ) : BuilderGenerator(model, symbolProvider, shape.inputShape(model)) { + private val runtimeConfig = symbolProvider.config().runtimeConfig + override fun buildFn(implBlockWriter: RustWriter) { val fallibleBuilder = StructureGenerator.fallibleBuilder(shape.inputShape(model), symbolProvider) val retryType = "()" @@ -72,15 +74,16 @@ class OperationInputBuilderGenerator( val outputSymbol = symbolProvider.toSymbol(shape) implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) - implBlockWriter.rustBlock("pub fn build(self, _config: &#T::Config) -> $returnType", RuntimeType.Config, RuntimeType.Operation(symbolProvider.config().runtimeConfig), outputSymbol) { + implBlockWriter.rustBlock("pub fn build(self, _config: &#T::Config) -> $returnType", RuntimeType.Config, RuntimeType.Operation(runtimeConfig), outputSymbol) { conditionalBlock("Ok(", ")", conditional = fallibleBuilder) { withBlock("let op = #T::new(", ");", outputSymbol) { coreBuilder(this) } rust( """ - let request = operation::Request::new(op.build_http_request().map(|body|operation::SdkBody::from(body))); - """ + let mut request = #T::Request::new(op.build_http_request().map(|body|#T::from(body))); + """, + RuntimeType.OperationModule(runtimeConfig), RuntimeType.SdkBody(runtimeConfig), ) plugins.forEach { it.section(OperationSection.Plugin)(this) } rust( diff --git a/rust-runtime/smithy-http/src/body.rs b/rust-runtime/smithy-http/src/body.rs index dea1386d92..3753096dbb 100644 --- a/rust-runtime/smithy-http/src/body.rs +++ b/rust-runtime/smithy-http/src/body.rs @@ -19,6 +19,7 @@ type BodyError = Box; /// /// TODO: Consider renaming to simply `Body`, although I'm concerned about naming headaches /// between hyper::Body and our Body +#[derive(Debug)] pub enum SdkBody { Once(Option), // TODO: tokio::sync::mpsc based streaming body diff --git a/rust-runtime/smithy-http/src/operation.rs b/rust-runtime/smithy-http/src/operation.rs index d4586c49f4..35e8e06cec 100644 --- a/rust-runtime/smithy-http/src/operation.rs +++ b/rust-runtime/smithy-http/src/operation.rs @@ -36,6 +36,14 @@ impl Operation { pub fn retry_policy(&self) -> &R { &self._retry_policy } + + pub fn with_policy(self, r: T) -> Operation { + Operation { + request: self.request, + response_handler: self.response_handler, + _retry_policy: r + } + } } pub struct Request { From cdb014393983fed55acd2b0e485873684a648d3f Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 25 Jan 2021 11:21:44 -0500 Subject: [PATCH 35/50] get all tests passing again --- .../codegen/smithy/generators/BuilderGenerator.kt | 5 +++-- .../smithy/generators/HttpProtocolTestGenerator.kt | 12 ++++++------ .../rust/codegen/smithy/protocols/AwsRestJson.kt | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index 0917981735..30fc836532 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -75,13 +75,14 @@ class OperationInputBuilderGenerator( implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) implBlockWriter.rustBlock("pub fn build(self, _config: &#T::Config) -> $returnType", RuntimeType.Config, RuntimeType.Operation(runtimeConfig), outputSymbol) { - conditionalBlock("Ok(", ")", conditional = fallibleBuilder) { + conditionalBlock("Ok({", "})", conditional = fallibleBuilder) { withBlock("let op = #T::new(", ");", outputSymbol) { coreBuilder(this) } rust( """ - let mut request = #T::Request::new(op.build_http_request().map(|body|#T::from(body))); + ##[allow(unused_mut)] + let mut request = #T::Request::new(op.build_http_request().map(#T::from)); """, RuntimeType.OperationModule(runtimeConfig), RuntimeType.SdkBody(runtimeConfig), ) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolTestGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolTestGenerator.kt index 918bef77e7..13bc9e5e6b 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolTestGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolTestGenerator.kt @@ -151,11 +151,11 @@ class HttpProtocolTestGenerator( writeInline("let input =") instantiator.render(this, inputShape, httpRequestTestCase.params) write(";") - if (protocolSupport.requestBodySerialization) { - write("let http_request = input.build_http_request();") - } else { + // if (protocolSupport.requestBodySerialization) { + write("let (http_request, _) = input.into_request_response().0.into_parts();") + /*} else { write("let http_request = ${protocolConfig.symbolProvider.toSymbol(inputShape).name}::assemble(input.input.request_builder_base(), vec![]);") - } + }*/ with(httpRequestTestCase) { write( """ @@ -248,12 +248,12 @@ class HttpProtocolTestGenerator( private fun checkBody(rustWriter: RustWriter, body: String, mediaType: String?) { if (body == "") { rustWriter.write("// No body") - rustWriter.write("assert!(&http_request.body().is_empty());") + rustWriter.write("assert!(&http_request.body().bytes().expect(\"should be strict\").is_empty());") } else { // When we generate a body instead of a stub, drop the trailing `;` and enable the assertion assertOk(rustWriter) { rustWriter.write( - "#T(&http_request.body(), ${ + "#T(&http_request.body().bytes().expect(\"body should be strict\"), ${ rustWriter.escape(body).dq() }, #T::from(${(mediaType ?: "unknown").dq()}))", RuntimeType.ProtocolTestHelper(protocolConfig.runtimeConfig, "validate_body"), diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsRestJson.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsRestJson.kt index 7507936a23..942a29aa0d 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsRestJson.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsRestJson.kt @@ -64,7 +64,7 @@ class AwsRestJsonGenerator( override fun toBodyImpl(implBlockWriter: RustWriter, inputShape: StructureShape, inputBody: StructureShape?) { bodyBuilderFun(implBlockWriter) { - write("todo!()") + rust(""""body not supported".into()""") } } From 694c16f41f044e762740c3ade7506ab24188c2b7 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 25 Jan 2021 11:44:26 -0500 Subject: [PATCH 36/50] Fix tests --- aws/rust-runtime/aws-hyper/src/lib.rs | 32 ++++++++++++------- aws/rust-runtime/operationwip/src/endpoint.rs | 4 +-- aws/rust-runtime/operationwip/src/lib.rs | 1 - .../operationwip/src/middleware.rs | 24 ++++++++------ aws/rust-runtime/operationwip/src/region.rs | 12 +++---- .../operationwip/src/signing_middleware.rs | 10 +++--- 6 files changed, 47 insertions(+), 36 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 7bf2658f19..f7431d7cd9 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -163,6 +163,8 @@ where } } +type BoxedResultFuture = Pin>>>; + impl tower::Service> for ParseResponseService where S: Service, Error = OperationError>, @@ -175,7 +177,7 @@ where { type Response = SdkSuccess; type Error = SdkError; - type Future = Pin>>>; + type Future = BoxedResultFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx).map_err(operation_error) @@ -240,11 +242,11 @@ use operationwip::endpoint::AddEndpointStage; use operationwip::middleware::{DispatchLayer, OperationPipelineService}; use operationwip::retry_policy::RetryPolicy; use operationwip::signing_middleware::SignRequestStage; +use smithy_http::operation::Operation; use std::fmt::Debug; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -use smithy_http::operation::Operation; use std::time::Duration; async fn read_body(body: B) -> Result, B::Error> { @@ -267,21 +269,21 @@ mod test { use bytes::Bytes; use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; - use operationwip::endpoint::{StaticEndpoint, EndpointProviderExt}; + use operationwip::endpoint::{EndpointProviderExt, StaticEndpoint}; use operationwip::region::Region; use operationwip::signing_middleware::SigningConfigExt; - use smithy_http::operation::Operation; use pin_utils::core_reexport::task::{Context, Poll}; - use std::time::Duration; + use smithy_http::body::SdkBody; + use smithy_http::operation; + use smithy_http::operation::Operation; + use smithy_http::response::ParseHttpResponse; use std::error::Error; use std::fmt::Formatter; use std::future::Future; use std::pin::Pin; use std::sync::{mpsc, Arc}; + use std::time::Duration; use std::time::UNIX_EPOCH; - use smithy_http::body::SdkBody; - use smithy_http::response::ParseHttpResponse; - use smithy_http::operation; #[derive(Clone)] struct TestService { @@ -349,17 +351,23 @@ mod test { .uri("/some_url") .body(SdkBody::from("Hello")) .unwrap(), - ).augment(|req, config| { + ) + .augment(|req, config| { config.insert(Region::new("some-region")); config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - config.insert_signing_config(auth::OperationSigningConfig::default_config("some-service")); + config.insert_signing_config(auth::OperationSigningConfig::default_config( + "some-service", + )); use operationwip::signing_middleware::CredentialProviderExt; - config.insert_credentials_provider(Arc::new(Credentials::from_static("access", "secret"))); + config.insert_credentials_provider(Arc::new(Credentials::from_static( + "access", "secret", + ))); config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( "http://localhost:8000", )))); Result::<_, ()>::Ok(req) - }).expect("valid request"); + }) + .expect("valid request"); let operation = Operation::new(request, TestOperationParser); diff --git a/aws/rust-runtime/operationwip/src/endpoint.rs b/aws/rust-runtime/operationwip/src/endpoint.rs index 5db3c97ad0..f0f2e44eed 100644 --- a/aws/rust-runtime/operationwip/src/endpoint.rs +++ b/aws/rust-runtime/operationwip/src/endpoint.rs @@ -10,10 +10,10 @@ use http::uri::Uri; use crate::middleware::OperationMiddleware; use http::header::HOST; -use std::sync::Arc; -use tower::BoxError; use smithy_http::operation; use smithy_http::property_bag::PropertyBag; +use std::sync::Arc; +use tower::BoxError; pub struct StaticEndpoint(http::Uri); diff --git a/aws/rust-runtime/operationwip/src/lib.rs b/aws/rust-runtime/operationwip/src/lib.rs index 2b613ef8bf..bda0d0ce3a 100644 --- a/aws/rust-runtime/operationwip/src/lib.rs +++ b/aws/rust-runtime/operationwip/src/lib.rs @@ -1,4 +1,3 @@ - pub mod endpoint; pub mod middleware; pub mod region; diff --git a/aws/rust-runtime/operationwip/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs index 46ca5d5d37..24ab586219 100644 --- a/aws/rust-runtime/operationwip/src/middleware.rs +++ b/aws/rust-runtime/operationwip/src/middleware.rs @@ -174,15 +174,17 @@ where #[cfg(test)] mod test { - use crate::middleware::{DispatchLayer, OperationMiddleware, OperationPipelineService}; - use crate::{ParseHttpResponse, SdkBody}; - + use crate::middleware::{ + BoxError, DispatchLayer, OperationMiddleware, OperationPipelineService, + }; use bytes::Bytes; use http::header::HeaderName; use http::{HeaderValue, Request, Response}; - use std::error::Error; use std::str::FromStr; + use smithy_http::body::SdkBody; + use smithy_http::operation; + use smithy_http::response::ParseHttpResponse; use tower::service_fn; use tower::{Layer, Service}; @@ -208,12 +210,14 @@ mod test { #[derive(Clone)] struct AddHeader(String, String); impl OperationMiddleware for AddHeader { - fn apply(&self, mut request: operation::Request) -> Result> { - request.base.headers_mut().append( - HeaderName::from_str(&self.0).unwrap(), - HeaderValue::from_str(&self.0).unwrap(), - ); - Ok(request) + fn apply(&self, request: operation::Request) -> Result { + request.augment(|mut request, _| { + request.headers_mut().append( + HeaderName::from_str(&self.0).unwrap(), + HeaderValue::from_str(&self.0).unwrap(), + ); + Ok(request) + }) } } diff --git a/aws/rust-runtime/operationwip/src/region.rs b/aws/rust-runtime/operationwip/src/region.rs index 06db427ac6..d22e5145aa 100644 --- a/aws/rust-runtime/operationwip/src/region.rs +++ b/aws/rust-runtime/operationwip/src/region.rs @@ -68,16 +68,16 @@ impl RegionExt for PropertyBag { #[cfg(test)] mod test { - use crate::extensions::Extensions; use crate::region::{Region, RegionExt, SigningRegion}; + use smithy_http::property_bag::PropertyBag; #[test] fn signing_region_fallback() { - let mut extensions = Extensions::new(); - extensions.insert(Region::new("aws-global")); - assert_eq!(extensions.signing_region(), Some("aws-global")); + let mut property_bag = PropertyBag::new(); + property_bag.insert(Region::new("aws-global")); + assert_eq!(property_bag.signing_region(), Some("aws-global")); - extensions.insert(SigningRegion::new("us-east-1")); - assert_eq!(extensions.signing_region(), Some("us-east-1")) + property_bag.insert(SigningRegion::new("us-east-1")); + assert_eq!(property_bag.signing_region(), Some("us-east-1")) } } diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs index f60c59f66d..e5673cde63 100644 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -3,17 +3,17 @@ * SPDX-License-Identifier: Apache-2.0. */ use crate::middleware::OperationMiddleware; +use crate::region::RegionExt; use auth::{ HttpSigner, HttpSigningConfig, OperationSigningConfig, ProvideCredentials, RequestConfig, SigningConfig, }; use http::Request; +use smithy_http::operation; +use smithy_http::property_bag::PropertyBag; use std::sync::Arc; use std::time::SystemTime; use tower::BoxError; -use smithy_http::operation; -use smithy_http::property_bag::PropertyBag; -use crate::region::RegionExt; #[derive(Clone)] pub struct SignRequestStage { @@ -94,8 +94,8 @@ impl OperationMiddleware for SignRequestStage { let request_config = RequestConfig { request_ts: config .get::() - .map(|t| t.clone()) - .unwrap_or_else(|| SystemTime::now()), // TODO: replace with Extensions.now(); + .copied() + .unwrap_or_else(SystemTime::now), // TODO: replace with Extensions.now(); region: region.into(), }; let signing_config = SigningConfig::Http(HttpSigningConfig { From 13699e32249dd566b9e90372e2cacebcf3bd5fad Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 25 Jan 2021 11:48:22 -0500 Subject: [PATCH 37/50] Update lock, fix sigv4 usage --- aws/rust-runtime/auth/src/lib.rs | 1 - aws/rust-runtime/test.sh | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index 6ec4209acf..f32cd3eb7e 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -185,7 +185,6 @@ impl HttpSigner { let date = signing_config.request_config.request_ts; for (key, value) in aws_sigv4::sign_core( request, - request.body(), &sigv4_creds, &signing_config.request_config.region, &signing_config.operation_config.service, diff --git a/aws/rust-runtime/test.sh b/aws/rust-runtime/test.sh index 1f5cd64f85..2a8b824b55 100755 --- a/aws/rust-runtime/test.sh +++ b/aws/rust-runtime/test.sh @@ -14,5 +14,6 @@ do (cd "$crate" && cargo fmt -- --check) (cd "$crate" && cargo clippy -- -D warnings) (cd "$crate" && cargo test) + (cd "$crate" && cargo doc --no-deps) fi done From 28015dcac4db1705edd9906c24ed1a6cb36101f3 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 26 Jan 2021 10:09:49 -0500 Subject: [PATCH 38/50] add ready_and --- aws/rust-runtime/auth/Cargo.toml | 2 +- aws/rust-runtime/aws-hyper/src/lib.rs | 119 +++++++++--------- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 3 - 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/aws/rust-runtime/auth/Cargo.toml b/aws/rust-runtime/auth/Cargo.toml index bcf53147d3..b90c84d4bf 100644 --- a/aws/rust-runtime/auth/Cargo.toml +++ b/aws/rust-runtime/auth/Cargo.toml @@ -9,7 +9,7 @@ description = "Authentication related functionality for the AWS Rust SDK. All in [dependencies] http = "0.2.2" -aws-sigv4 = { git = "https://github.com/rcoh/sigv4" } +aws-sigv4 = { git = "https://github.com/rcoh/sigv4", rev = "05f90abc02a868cb570ed3006d950947cc0898b0" } [dev-dependencies] tokio = { version = "1", features = ["full"]} diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index f7431d7cd9..125f41c95e 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -5,7 +5,7 @@ use smithy_http::body::SdkBody; use smithy_http::operation; use smithy_http::response::ParseHttpResponse; use std::error::Error; -use tower::{Layer, Service, ServiceBuilder}; +use tower::{Layer, Service, ServiceBuilder, ServiceExt}; type BoxError = Box; @@ -77,8 +77,8 @@ impl Client { } fn operation_error(o: OperationError) -> SdkError -where - OE: Into, + where + OE: Into, { match o { OperationError::DispatchError(e) => SdkError::DispatchFailure(e.into()), @@ -90,11 +90,11 @@ async fn load_response( mut response: http::Response, handler: &O, ) -> Result, SdkError> -where - B: http_body::Body + Unpin, - B: From + Debug + 'static, - B::Error: Error + Send + Sync + 'static, - O: ParseHttpResponse>, + where + B: http_body::Body + Unpin, + B: From + Debug + 'static, + B::Error: Error + Send + Sync + 'static, + O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { return sdk_result(parsed_response, response); @@ -125,11 +125,11 @@ pub struct ParseResponseService { struct RetryStrategy {} impl - tower::retry::Policy, Response, Error> for RetryStrategy -where - R: RetryPolicy, +tower::retry::Policy, Response, Error> for RetryStrategy + where + R: RetryPolicy, { - type Future = Pin>>; + type Future = Pin>>; fn retry( &self, @@ -153,8 +153,8 @@ where pub struct ParseResponseLayer; impl Layer for ParseResponseLayer -where - S: Service, + where + S: Service, { type Service = ParseResponseService; @@ -163,17 +163,17 @@ where } } -type BoxedResultFuture = Pin>>>; +type BoxedResultFuture = Pin>>>; impl tower::Service> for ParseResponseService -where - S: Service, Error = OperationError>, - OE: Into, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin + Debug + 'static, - B: From, - B::Error: Error + Send + Sync + 'static, + where + S: Service, Error=OperationError>, + OE: Into, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin + Debug + 'static, + B: From, + B::Error: Error + Send + Sync + 'static, { type Response = SdkSuccess; type Error = SdkError; @@ -197,21 +197,21 @@ where } impl Client -where - S: Service, Response = http::Response> + where + S: Service, Response=http::Response> + Send + Clone + 'static, - S::Error: Into + Send + Sync + 'static, - S::Future: Send + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { pub async fn call( &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationPipelineService::for_stage(SignRequestStage::new()); let endpoint_resolver = OperationPipelineService::for_stage(AddEndpointStage); @@ -221,15 +221,18 @@ where .ready_and() .await .map_err(|e| _SdkError::DispatchFailure(e.into()))?;*/ - let mut svc = ServiceBuilder::new() - .retry(RetryStrategy {}) - .layer(ParseResponseLayer) - .layer(endpoint_resolver) - .layer(signer) - .layer(DispatchLayer) - .service(inner); - - svc.call(input).await + let mut svc = + ServiceBuilder::new() + .retry(RetryStrategy {}) + .map_request(|r: Operation|r) + .layer(ParseResponseLayer) + .layer(endpoint_resolver) + .layer(signer) + .layer(DispatchLayer) + .service(inner); + svc.ready_and().await?.call(input).await + + //svc.call(input).await //todo!() } } @@ -303,7 +306,7 @@ mod test { impl tower::Service> for TestService { type Response = http::Response; type Error = BoxError; - type Future = Pin> + Send>>; + type Future = Pin> + Send>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -320,8 +323,8 @@ mod test { struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -352,22 +355,22 @@ mod test { .body(SdkBody::from("Hello")) .unwrap(), ) - .augment(|req, config| { - config.insert(Region::new("some-region")); - config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - config.insert_signing_config(auth::OperationSigningConfig::default_config( - "some-service", - )); - use operationwip::signing_middleware::CredentialProviderExt; - config.insert_credentials_provider(Arc::new(Credentials::from_static( - "access", "secret", - ))); - config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( - "http://localhost:8000", - )))); - Result::<_, ()>::Ok(req) - }) - .expect("valid request"); + .augment(|req, config| { + config.insert(Region::new("some-region")); + config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); + config.insert_signing_config(auth::OperationSigningConfig::default_config( + "some-service", + )); + use operationwip::signing_middleware::CredentialProviderExt; + config.insert_credentials_provider(Arc::new(Credentials::from_static( + "access", "secret", + ))); + config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + "http://localhost:8000", + )))); + Result::<_, ()>::Ok(req) + }) + .expect("valid request"); let operation = Operation::new(request, TestOperationParser); diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index 101f0c1f8b..ee72cc6975 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -148,10 +148,7 @@ dependencies = [ name = "dynamodb" version = "0.0.1" dependencies = [ - "auth", - "bytes", "http", - "operationwip", "rand 0.7.3", "serde", "serde_json", From f42f06c754a413d5483712e6468c5751a038cbad Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 26 Jan 2021 22:16:02 -0500 Subject: [PATCH 39/50] wip --- aws/rust-runtime/operationwip/src/endpoint.rs | 8 +++---- .../operationwip/src/middleware.rs | 23 ++++++++++++------- .../operationwip/src/signing_middleware.rs | 9 ++++---- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 1 + 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/aws/rust-runtime/operationwip/src/endpoint.rs b/aws/rust-runtime/operationwip/src/endpoint.rs index f0f2e44eed..dbf40dea2d 100644 --- a/aws/rust-runtime/operationwip/src/endpoint.rs +++ b/aws/rust-runtime/operationwip/src/endpoint.rs @@ -8,12 +8,11 @@ use std::str::FromStr; use http::uri::Uri; -use crate::middleware::OperationMiddleware; +use crate::middleware::RequestStage; use http::header::HOST; use smithy_http::operation; use smithy_http::property_bag::PropertyBag; use std::sync::Arc; -use tower::BoxError; pub struct StaticEndpoint(http::Uri); @@ -96,8 +95,9 @@ impl EndpointProviderExt for PropertyBag { #[derive(Clone, Copy)] /// Set the endpoint for a request based on the endpoint config pub struct AddEndpointStage; -impl OperationMiddleware for AddEndpointStage { - fn apply(&self, request: operation::Request) -> Result { +impl RequestStage for AddEndpointStage { + type Error = String; + fn apply(&self, request: operation::Request) -> Result { request.augment(|mut request, extensions| { let endpoint_provider: &Arc = extensions .endpoint_provider() diff --git a/aws/rust-runtime/operationwip/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs index 24ab586219..8d35be525e 100644 --- a/aws/rust-runtime/operationwip/src/middleware.rs +++ b/aws/rust-runtime/operationwip/src/middleware.rs @@ -13,8 +13,9 @@ use pin_project::pin_project; use smithy_http::body::SdkBody; use smithy_http::operation; -pub trait OperationMiddleware { - fn apply(&self, request: operation::Request) -> Result; +pub trait RequestStage { + type Error: Into; + fn apply(&self, request: operation::Request) -> Result; } #[derive(Clone)] @@ -48,7 +49,7 @@ where } pub trait RequestConstructionErr { - fn request_error(err: Box) -> Self; + fn request_error(err: BoxError) -> Self; } #[pin_project(project = EnumProj)] @@ -74,7 +75,7 @@ where impl Service for OperationRequestMiddlewareService where S: Service, - M: OperationMiddleware, + M: RequestStage, S::Error: RequestConstructionErr, { type Response = S::Response; @@ -89,7 +90,7 @@ where match self .middleware .apply(req) - .map_err(|e| S::Error::request_error(e)) + .map_err(|e| S::Error::request_error(e.into())) { Err(e) => OperationMiddlewareFuture::Ready(Some(e)), Ok(req) => OperationMiddlewareFuture::Inner(self.inner.call(req)), @@ -106,6 +107,10 @@ pub struct DispatchMiddleware { inner: S, } +pub fn to_request(request: operation::Request) -> Result, OperationError> { + Ok(request.into_parts().0) +} + #[derive(Clone, Copy)] pub struct DispatchLayer; @@ -175,7 +180,7 @@ where #[cfg(test)] mod test { use crate::middleware::{ - BoxError, DispatchLayer, OperationMiddleware, OperationPipelineService, + BoxError, DispatchLayer, RequestStage, OperationPipelineService, }; use bytes::Bytes; use http::header::HeaderName; @@ -187,6 +192,7 @@ mod test { use smithy_http::response::ParseHttpResponse; use tower::service_fn; use tower::{Layer, Service}; + use std::convert::Infallible; struct TestOperationParser; @@ -209,8 +215,9 @@ mod test { async fn middleware_test() { #[derive(Clone)] struct AddHeader(String, String); - impl OperationMiddleware for AddHeader { - fn apply(&self, request: operation::Request) -> Result { + impl RequestStage for AddHeader { + type Error = Infallible; + fn apply(&self, request: operation::Request) -> Result { request.augment(|mut request, _| { request.headers_mut().append( HeaderName::from_str(&self.0).unwrap(), diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs index e5673cde63..e75af58fd2 100644 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ -use crate::middleware::OperationMiddleware; +use crate::middleware::RequestStage; use crate::region::RegionExt; use auth::{ HttpSigner, HttpSigningConfig, OperationSigningConfig, ProvideCredentials, RequestConfig, @@ -76,8 +76,9 @@ impl CredentialProviderExt for PropertyBag { } } -impl OperationMiddleware for SignRequestStage { - fn apply(&self, request: operation::Request) -> Result { +impl RequestStage for SignRequestStage { + type Error = BoxError; + fn apply(&self, request: operation::Request) -> Result { request.augment(|request, config| { let operation_config = config.signing_config().ok_or("Missing signing config")?; let cred_provider = config @@ -95,7 +96,7 @@ impl OperationMiddleware for SignRequestStage { request_ts: config .get::() .copied() - .unwrap_or_else(SystemTime::now), // TODO: replace with Extensions.now(); + .unwrap_or_else(SystemTime::now), region: region.into(), }; let signing_config = SigningConfig::Http(HttpSigningConfig { diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index ee72cc6975..fcd67a51b8 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -148,6 +148,7 @@ dependencies = [ name = "dynamodb" version = "0.0.1" dependencies = [ + "bytes", "http", "rand 0.7.3", "serde", From 382cb86ec11b4f87d99f909101d81ea1ec751d36 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 26 Jan 2021 22:43:25 -0500 Subject: [PATCH 40/50] Split call from call_rwa --- aws/rust-runtime/aws-hyper/src/lib.rs | 127 ++++++++++-------- .../operationwip/src/middleware.rs | 15 ++- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 4 +- .../examples/dynamo-helloworld/src/main.rs | 6 +- rust-runtime/smithy-http/src/operation.rs | 10 +- 5 files changed, 91 insertions(+), 71 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 125f41c95e..8dbe208411 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -77,8 +77,8 @@ impl Client { } fn operation_error(o: OperationError) -> SdkError - where - OE: Into, +where + OE: Into, { match o { OperationError::DispatchError(e) => SdkError::DispatchFailure(e.into()), @@ -90,11 +90,11 @@ async fn load_response( mut response: http::Response, handler: &O, ) -> Result, SdkError> - where - B: http_body::Body + Unpin, - B: From + Debug + 'static, - B::Error: Error + Send + Sync + 'static, - O: ParseHttpResponse>, +where + B: http_body::Body + Unpin, + B: From + Debug + 'static, + B::Error: Error + Send + Sync + 'static, + O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { return sdk_result(parsed_response, response); @@ -125,11 +125,11 @@ pub struct ParseResponseService { struct RetryStrategy {} impl -tower::retry::Policy, Response, Error> for RetryStrategy - where - R: RetryPolicy, + tower::retry::Policy, Response, Error> for RetryStrategy +where + R: RetryPolicy, { - type Future = Pin>>; + type Future = Pin>>; fn retry( &self, @@ -153,8 +153,8 @@ tower::retry::Policy, Response, Error> for Retr pub struct ParseResponseLayer; impl Layer for ParseResponseLayer - where - S: Service, +where + S: Service, { type Service = ParseResponseService; @@ -163,17 +163,17 @@ impl Layer for ParseResponseLayer } } -type BoxedResultFuture = Pin>>>; +type BoxedResultFuture = Pin>>>; impl tower::Service> for ParseResponseService - where - S: Service, Error=OperationError>, - OE: Into, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin + Debug + 'static, - B: From, - B::Error: Error + Send + Sync + 'static, +where + S: Service, Error = OperationError>, + OE: Into, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin + Debug + 'static, + B: From, + B::Error: Error + Send + Sync + 'static, { type Response = SdkSuccess; type Error = SdkError; @@ -197,21 +197,33 @@ impl tower::Service> for ParseR } impl Client - where - S: Service, Response=http::Response> +where + S: Service, Response = http::Response> + Send + Clone + 'static, - S::Error: Into + Send + Sync + 'static, - S::Future: Send + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { - pub async fn call( + /// Dispatch this request to the network + /// + /// For ergonomics, this does not include the raw response for successful responses. To + /// access the raw response use `call_raw`. + pub async fn call(&self, input: Operation) -> Result> + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + { + self.call_raw(input).await.map(|res| res.parsed) + } + + pub async fn call_raw( &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationPipelineService::for_stage(SignRequestStage::new()); let endpoint_resolver = OperationPipelineService::for_stage(AddEndpointStage); @@ -221,15 +233,14 @@ impl Client .ready_and() .await .map_err(|e| _SdkError::DispatchFailure(e.into()))?;*/ - let mut svc = - ServiceBuilder::new() - .retry(RetryStrategy {}) - .map_request(|r: Operation|r) - .layer(ParseResponseLayer) - .layer(endpoint_resolver) - .layer(signer) - .layer(DispatchLayer) - .service(inner); + let mut svc = ServiceBuilder::new() + .retry(RetryStrategy {}) + .map_request(|r: Operation| r) + .layer(ParseResponseLayer) + .layer(endpoint_resolver) + .layer(signer) + .layer(DispatchLayer) + .service(inner); svc.ready_and().await?.call(input).await //svc.call(input).await @@ -306,7 +317,7 @@ mod test { impl tower::Service> for TestService { type Response = http::Response; type Error = BoxError; - type Future = Pin> + Send>>; + type Future = Pin> + Send>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -323,8 +334,8 @@ mod test { struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -355,22 +366,22 @@ mod test { .body(SdkBody::from("Hello")) .unwrap(), ) - .augment(|req, config| { - config.insert(Region::new("some-region")); - config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - config.insert_signing_config(auth::OperationSigningConfig::default_config( - "some-service", - )); - use operationwip::signing_middleware::CredentialProviderExt; - config.insert_credentials_provider(Arc::new(Credentials::from_static( - "access", "secret", - ))); - config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( - "http://localhost:8000", - )))); - Result::<_, ()>::Ok(req) - }) - .expect("valid request"); + .augment(|req, config| { + config.insert(Region::new("some-region")); + config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); + config.insert_signing_config(auth::OperationSigningConfig::default_config( + "some-service", + )); + use operationwip::signing_middleware::CredentialProviderExt; + config.insert_credentials_provider(Arc::new(Credentials::from_static( + "access", "secret", + ))); + config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + "http://localhost:8000", + )))); + Result::<_, ()>::Ok(req) + }) + .expect("valid request"); let operation = Operation::new(request, TestOperationParser); diff --git a/aws/rust-runtime/operationwip/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs index 8d35be525e..30d092f369 100644 --- a/aws/rust-runtime/operationwip/src/middleware.rs +++ b/aws/rust-runtime/operationwip/src/middleware.rs @@ -107,7 +107,9 @@ pub struct DispatchMiddleware { inner: S, } -pub fn to_request(request: operation::Request) -> Result, OperationError> { +pub fn to_request( + request: operation::Request, +) -> Result, OperationError> { Ok(request.into_parts().0) } @@ -179,9 +181,7 @@ where #[cfg(test)] mod test { - use crate::middleware::{ - BoxError, DispatchLayer, RequestStage, OperationPipelineService, - }; + use crate::middleware::{BoxError, DispatchLayer, OperationPipelineService, RequestStage}; use bytes::Bytes; use http::header::HeaderName; use http::{HeaderValue, Request, Response}; @@ -190,9 +190,9 @@ mod test { use smithy_http::body::SdkBody; use smithy_http::operation; use smithy_http::response::ParseHttpResponse; + use std::convert::Infallible; use tower::service_fn; use tower::{Layer, Service}; - use std::convert::Infallible; struct TestOperationParser; @@ -217,7 +217,10 @@ mod test { struct AddHeader(String, String); impl RequestStage for AddHeader { type Error = Infallible; - fn apply(&self, request: operation::Request) -> Result { + fn apply( + &self, + request: operation::Request, + ) -> Result { request.augment(|mut request, _| { request.headers_mut().append( HeaderName::from_str(&self.0).unwrap(), diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index fcd67a51b8..bbb7e027b2 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "aws-sigv4" version = "0.0.1" -source = "git+https://github.com/rcoh/sigv4#ef394a689c695f057ce9870b38bf4b470efcfc36" +source = "git+https://github.com/rcoh/sigv4?rev=05f90abc02a868cb570ed3006d950947cc0898b0#05f90abc02a868cb570ed3006d950947cc0898b0" dependencies = [ "bytes", "chrono", @@ -148,8 +148,10 @@ dependencies = [ name = "dynamodb" version = "0.0.1" dependencies = [ + "auth", "bytes", "http", + "operationwip", "rand 0.7.3", "serde", "serde_json", diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 8d5d1f6d1c..160ddd1067 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -68,7 +68,7 @@ async fn main() -> Result<(), Box> { let response = client.call(list_tables).await; let tables = match response { - Ok(output) => output.parsed.table_names.unwrap(), + Ok(output) => output.table_names.unwrap(), Err(e) => panic!("err: {:?}", e), }; if tables.is_empty() { @@ -90,7 +90,7 @@ async fn main() -> Result<(), Box> { ) .build(&config); match client.call(create_table).await { - Ok(created) => println!("table created! {:#?}", created.parsed), + Ok(created) => println!("table created! {:#?}", created), Err(failed) => println!("failed to create table: {:?}", failed), } } @@ -102,7 +102,7 @@ async fn main() -> Result<(), Box> { Ok(output) => { println!( "tables: {:?}", - output.parsed.table_names.unwrap_or_default() + output.table_names.unwrap_or_default() ); } Err(e) => panic!("err: {:?}", e.error()), diff --git a/rust-runtime/smithy-http/src/operation.rs b/rust-runtime/smithy-http/src/operation.rs index 35e8e06cec..86191b561c 100644 --- a/rust-runtime/smithy-http/src/operation.rs +++ b/rust-runtime/smithy-http/src/operation.rs @@ -19,8 +19,12 @@ impl Operation { } } -impl Operation { - pub fn try_clone(&self) -> Option where H: Clone, R: Clone { +impl Operation { + pub fn try_clone(&self) -> Option + where + H: Clone, + R: Clone, + { let inner = self.request.try_clone()?; Some(Operation { request: inner, @@ -41,7 +45,7 @@ impl Operation { Operation { request: self.request, response_handler: self.response_handler, - _retry_policy: r + _retry_policy: r, } } } From 9f0689dcfd8cd9414a0b50e0ac39df7d1c95fba7 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Thu, 28 Jan 2021 18:06:30 -0500 Subject: [PATCH 41/50] Add missing aws-sig-auth files --- aws/rust-runtime/aws-sig-auth/Cargo.toml | 15 +++ aws/rust-runtime/aws-sig-auth/src/lib.rs | 117 +++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 aws/rust-runtime/aws-sig-auth/Cargo.toml create mode 100644 aws/rust-runtime/aws-sig-auth/src/lib.rs diff --git a/aws/rust-runtime/aws-sig-auth/Cargo.toml b/aws/rust-runtime/aws-sig-auth/Cargo.toml new file mode 100644 index 0000000000..a3f76c6ace --- /dev/null +++ b/aws/rust-runtime/aws-sig-auth/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "aws-sig-auth" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +http = "0.2.2" +aws-sigv4 = { git = "https://github.com/rcoh/sigv4", rev = "05f90abc02a868cb570ed3006d950947cc0898b0" } +auth = { path = "../auth" } + +[dev-dependencies] +tokio = { version = "1", features = ["full"]} diff --git a/aws/rust-runtime/aws-sig-auth/src/lib.rs b/aws/rust-runtime/aws-sig-auth/src/lib.rs new file mode 100644 index 0000000000..fed9787057 --- /dev/null +++ b/aws/rust-runtime/aws-sig-auth/src/lib.rs @@ -0,0 +1,117 @@ +use std::borrow::Cow; +use std::time::SystemTime; +use std::error::Error; +use auth::Credentials; + +#[derive(Eq, PartialEq, Clone, Copy)] +pub enum SigningAlgorithm { + SigV4, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +pub enum HttpSignatureType { + /// A signature for a full http request should be computed, with header updates applied to the signing result. + HttpRequestHeaders, + /// A signature for a full http request should be computed, with query param updates applied to the signing result. + HttpRequestQueryParams, +} + +pub enum SigningConfig { + Http(HttpSigningConfig), + // Http Chunked Body + // Event Stream +} + +impl OperationSigningConfig { + pub fn default_config(service: &'static str) -> Self { + OperationSigningConfig { + algorithm: SigningAlgorithm::SigV4, + signature_type: HttpSignatureType::HttpRequestHeaders, + service: service.into(), + double_uri_encode: false, + normalize_uri_path: true, + omit_session_token: false, + } + } +} + +pub struct HttpSigningConfig { + pub operation_config: OperationSigningConfig, + pub request_config: RequestConfig, +} + +#[derive(Clone, PartialEq, Eq)] +pub struct OperationSigningConfig { + pub algorithm: SigningAlgorithm, + pub signature_type: HttpSignatureType, + pub service: Cow<'static, str>, + + pub double_uri_encode: bool, + pub normalize_uri_path: bool, + pub omit_session_token: bool, +} + +pub struct RequestConfig { + // the request config must enable recomputing the timestamp for retries, etc. + pub request_ts: SystemTime, + pub region: Cow<'static, str>, +} + +type SigningError = Box; + +#[derive(Clone)] +pub struct HttpSigner {} + +impl HttpSigner { + /// Sign an HTTP request + /// + /// You may need to modify the body of your HTTP request to be signable. + /// + /// NOTE: This design may change, a modified design that returns a SigningResult may be + /// used instead, this design allows for current compatibility with `aws-sigv4` + pub fn sign( + &self, + signing_config: &HttpSigningConfig, + credentials: &Credentials, + request: &mut http::Request, + ) -> Result<(), SigningError> + where + B: AsRef<[u8]>, + { + let operation_config = &signing_config.operation_config; + if operation_config.algorithm != SigningAlgorithm::SigV4 + || operation_config.double_uri_encode + || !operation_config.normalize_uri_path + || operation_config.omit_session_token + || operation_config.signature_type != HttpSignatureType::HttpRequestHeaders + { + unimplemented!() + } + // TODO: update the aws_sigv4 API to avoid needing the clone the credentials + let sigv4_creds = aws_sigv4::Credentials { + access_key: credentials.access_key_id().to_string(), + secret_key: credentials.secret_access_key().to_string(), + security_token: credentials.session_token().map(|s|s.to_string()), + }; + let date = signing_config.request_config.request_ts; + for (key, value) in aws_sigv4::sign_core( + request, + &sigv4_creds, + &signing_config.request_config.region, + &signing_config.operation_config.service, + date, + ) { + request + .headers_mut() + .append(key.header_name(), value.parse()?); + } + + Ok(()) + } +} + +#[cfg(test)] +mod test { + #[test] + fn hello() {} +} From 4adcaa73a97360588571aaca3e5fea0dffc37909 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 2 Feb 2021 08:47:09 -0500 Subject: [PATCH 42/50] Demo integration with the crucible ITs --- aws/rust-runtime/aws-hyper/src/lib.rs | 110 +++++++++++--------- aws/sdk/integration-tests/tests/dynamodb.rs | 94 +++++++++++++++++ 2 files changed, 153 insertions(+), 51 deletions(-) create mode 100644 aws/sdk/integration-tests/tests/dynamodb.rs diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 237b02cf70..ceb7d03bed 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -60,6 +60,14 @@ pub struct Client { inner: S, } +impl Client { + pub fn new(connector: S) -> Self { + Client { + inner: connector + } + } +} + impl Client, SdkBody>> { pub fn default() -> Self { let https = HttpsConnector::new(); @@ -77,8 +85,8 @@ impl Client { } fn operation_error(o: OperationError) -> SdkError -where - OE: Into, + where + OE: Into, { match o { OperationError::DispatchError(e) => SdkError::DispatchFailure(e.into()), @@ -90,11 +98,11 @@ async fn load_response( mut response: http::Response, handler: &O, ) -> Result, SdkError> -where - B: http_body::Body + Unpin, - B: From + Debug + 'static, - B::Error: Error + Send + Sync + 'static, - O: ParseHttpResponse>, + where + B: http_body::Body + Unpin, + B: From + Debug + 'static, + B::Error: Error + Send + Sync + 'static, + O: ParseHttpResponse>, { if let Some(parsed_response) = handler.parse_unloaded(&mut response) { return sdk_result(parsed_response, response); @@ -125,11 +133,11 @@ pub struct ParseResponseService { struct RetryStrategy {} impl - tower::retry::Policy, Response, Error> for RetryStrategy -where - R: RetryPolicy, +tower::retry::Policy, Response, Error> for RetryStrategy + where + R: RetryPolicy, { - type Future = Pin>>; + type Future = Pin>>; fn retry( &self, @@ -153,8 +161,8 @@ where pub struct ParseResponseLayer; impl Layer for ParseResponseLayer -where - S: Service, + where + S: Service, { type Service = ParseResponseService; @@ -163,17 +171,17 @@ where } } -type BoxedResultFuture = Pin>>>; +type BoxedResultFuture = Pin>>>; impl tower::Service> for ParseResponseService -where - S: Service, Error = OperationError>, - OE: Into, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin + Debug + 'static, - B: From, - B::Error: Error + Send + Sync + 'static, + where + S: Service, Error=OperationError>, + OE: Into, + S::Future: 'static, + O: ParseHttpResponse> + 'static, + B: http_body::Body + Unpin + Debug + 'static, + B: From, + B::Error: Error + Send + Sync + 'static, { type Response = SdkSuccess; type Error = SdkError; @@ -197,22 +205,22 @@ where } impl Client -where - S: Service, Response = http::Response> + where + S: Service, Response=http::Response> + Send + Clone + 'static, - S::Error: Into + Send + Sync + 'static, - S::Future: Send + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { /// Dispatch this request to the network /// /// For ergonomics, this does not include the raw response for successful responses. To /// access the raw response use `call_raw`. pub async fn call(&self, input: Operation) -> Result> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { self.call_raw(input).await.map(|res| res.parsed) } @@ -221,9 +229,9 @@ where &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationPipelineService::for_stage(SignRequestStage::new()); let endpoint_resolver = OperationPipelineService::for_stage(AddEndpointStage); @@ -318,7 +326,7 @@ mod test { impl tower::Service> for TestService { type Response = http::Response; type Error = BoxError; - type Future = Pin> + Send>>; + type Future = Pin> + Send>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -335,8 +343,8 @@ mod test { struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -367,22 +375,22 @@ mod test { .body(SdkBody::from("Hello")) .unwrap(), ) - .augment(|req, config| { - config.insert(Region::new("some-region")); - config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - config.insert_signing_config(OperationSigningConfig::default_config( - "some-service", - )); - use operationwip::signing_middleware::CredentialProviderExt; - config.insert_credentials_provider(Arc::new(Credentials::from_keys( - "access", "secret", None - ))); - config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( - "http://localhost:8000", - )))); - Result::<_, ()>::Ok(req) - }) - .expect("valid request"); + .augment(|req, config| { + config.insert(Region::new("some-region")); + config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); + config.insert_signing_config(OperationSigningConfig::default_config( + "some-service", + )); + use operationwip::signing_middleware::CredentialProviderExt; + config.insert_credentials_provider(Arc::new(Credentials::from_keys( + "access", "secret", None, + ))); + config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + "http://localhost:8000", + )))); + Result::<_, ()>::Ok(req) + }) + .expect("valid request"); let operation = Operation::new(request, TestOperationParser); diff --git a/aws/sdk/integration-tests/tests/dynamodb.rs b/aws/sdk/integration-tests/tests/dynamodb.rs new file mode 100644 index 0000000000..3b79fc92c1 --- /dev/null +++ b/aws/sdk/integration-tests/tests/dynamodb.rs @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use auth::Credentials; +use bytes::Bytes; +use dynamodb::operation::ListTables; +use smithy_http::body::SdkBody; +use std::convert::{TryFrom}; +use std::process::Command; +use serde::Deserialize; +use tower::BoxError; +use reqwest::Certificate; +use std::fs; + +fn start_test(id: &str) { + let _output = Command::new("curl") + .args(&[format!("http://crucible/clear_test")]) + .output() + .expect("test started"); + let _output = Command::new("curl") + .args(&[format!("http://crucible/start_test/{}", id)]) + .output() + .expect("test started"); +} + +fn finish_test() -> TestResults { + let output = Command::new("curl") + .args(&[format!("http://crucible/check_test")]) + .output() + .expect("test started"); + serde_json::from_slice(output.stdout.as_slice()).expect("invalid schema") +} + +#[derive(Deserialize)] +struct TestResults { + errors: Vec +} + +fn make_connector() -> impl tower::Service< + http::Request, + Response = http::Response, + Error = BoxError, + Future = impl Send +> + Clone { + tower::service_fn(|req: http::Request| async move { + let cert = fs::read_to_string("/Users/rcoh/.mitmproxy/mitmproxy-ca-cert.pem").expect("loading cert"); + let cert = Certificate::from_pem(cert.as_bytes()).expect("couldn't load cert"); + let client = reqwest::ClientBuilder::new().add_root_certificate(cert).build().expect("build client"); + let req = req.map(|body| Bytes::copy_from_slice(body.bytes().unwrap())); + let req = reqwest::Request::try_from(req).map_err(|_| "not a request")?; + let response = client.execute(req).await.unwrap(); + let mut builder = http::Response::builder().status(response.status()); + *(builder.headers_mut().unwrap()) = response.headers().clone(); + let data = response.bytes().await.unwrap(); + Result::, BoxError>::Ok( + builder + .body(hyper::Body::from(data)) + .unwrap(), + ) + }) +} + +#[tokio::test] +async fn test_list_tables() { + let config = dynamodb::Config::builder() + .region("us-east-1") + .credentials_provider(Credentials::from_keys("asdf", "asdf", None)) + .build(); + let client = aws_hyper::Client::new(make_connector()); + let request = ListTables::builder().build(&config); + + start_test("list-tables"); + let response = client.call(request).await.expect("success response"); + assert_eq!(response.table_names.unwrap(), vec!["new_table".to_owned()]); + let output = finish_test(); + assert_eq!(output.errors, Vec::::new()); +} + +#[tokio::test] +async fn test_invalid_response() { + let config = dynamodb::Config::builder() + .region("us-east-1") + .credentials_provider(Credentials::from_keys("asdf", "asdf", None)) + .build(); + let client = aws_hyper::Client::new(make_connector()); + let request = ListTables::builder().build(&config); + + start_test("invalid-response"); + let _ = client.call(request).await.expect_err("response does not contain valid JSON"); + let output = finish_test(); + assert_eq!(output.errors, Vec::::new()); +} From c07720f8cf593e3d675bd3f6ab242ef9af80f6c7 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Sun, 7 Feb 2021 21:30:04 -0500 Subject: [PATCH 43/50] Cleanup code in AWS hyper --- aws/rust-runtime/auth/src/lib.rs | 13 +- aws/rust-runtime/auth/src/provider.rs | 28 +-- aws/rust-runtime/aws-hyper/src/lib.rs | 211 +++++------------- aws/rust-runtime/aws-sig-auth/src/lib.rs | 10 +- .../operationwip/src/middleware.rs | 2 +- .../operationwip/src/signing_middleware.rs | 5 +- .../examples/dynamo-helloworld/src/main.rs | 5 +- .../smithy/generators/BuilderGenerator.kt | 2 - .../generators/HttpProtocolGenerator.kt | 3 - .../codegen/smithy/protocols/AwsJson10.kt | 15 -- rust-runtime/smithy-http/src/result.rs | 32 ++- 11 files changed, 120 insertions(+), 206 deletions(-) diff --git a/aws/rust-runtime/auth/src/lib.rs b/aws/rust-runtime/auth/src/lib.rs index f6a2e5ee02..71aa9c6423 100644 --- a/aws/rust-runtime/auth/src/lib.rs +++ b/aws/rust-runtime/auth/src/lib.rs @@ -1,9 +1,9 @@ pub mod provider; -use std::time::SystemTime; use std::error::Error; -use std::fmt::{Display, Formatter, Debug}; use std::fmt; +use std::fmt::{Debug, Display, Formatter}; +use std::time::SystemTime; /// AWS SDK Credentials /// @@ -50,7 +50,7 @@ impl Credentials { session_token, expires_after: None, - provider_name: STATIC_CREDENTIALS + provider_name: STATIC_CREDENTIALS, } } @@ -71,14 +71,14 @@ impl Credentials { #[non_exhaustive] pub enum CredentialsError { CredentialsNotLoaded, - Unhandled(Box) + Unhandled(Box), } impl Display for CredentialsError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { CredentialsError::CredentialsNotLoaded => write!(f, "CredentialsNotLoaded"), - CredentialsError::Unhandled(err) => write!(f, "{}", err) + CredentialsError::Unhandled(err) => write!(f, "{}", err), } } } @@ -87,7 +87,7 @@ impl Error for CredentialsError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { CredentialsError::Unhandled(e) => Some(e.as_ref() as _), - _ => None + _ => None, } } } @@ -102,7 +102,6 @@ pub trait ProvideCredentials: Send + Sync { fn credentials(&self) -> Result; } - pub fn default_provider() -> impl ProvideCredentials { // TODO: this should be a chain based on the CRT provider::EnvironmentVariableCredentialsProvider::new() diff --git a/aws/rust-runtime/auth/src/provider.rs b/aws/rust-runtime/auth/src/provider.rs index e6e4e768b6..22ae7d416c 100644 --- a/aws/rust-runtime/auth/src/provider.rs +++ b/aws/rust-runtime/auth/src/provider.rs @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0. */ -use crate::{ProvideCredentials, Credentials, CredentialsError}; -use std::env::VarError; +use crate::{Credentials, CredentialsError, ProvideCredentials}; use std::collections::HashMap; +use std::env::VarError; /// Load Credentials from Environment Variables pub struct EnvironmentVariableCredentialsProvider { - env: Box Result + Send + Sync> + env: Box Result + Send + Sync>, } impl EnvironmentVariableCredentialsProvider { @@ -21,8 +21,10 @@ impl EnvironmentVariableCredentialsProvider { pub fn for_map(env: HashMap) -> Self { EnvironmentVariableCredentialsProvider { env: Box::new(move |key: &str| { - env.get(key).ok_or(VarError::NotPresent).map(|k|k.to_string()) - }) + env.get(key) + .ok_or(VarError::NotPresent) + .map(|k| k.to_string()) + }), } } } @@ -36,15 +38,16 @@ const ENV_PROVIDER: &'static str = "EnvironmentVariable"; impl ProvideCredentials for EnvironmentVariableCredentialsProvider { fn credentials(&self) -> Result { let access_key = (self.env)("AWS_ACCESS_KEY_ID").map_err(to_cred_error)?; - let secret_key = - (self.env)("AWS_SECRET_ACCESS_KEY").or_else(|_|(self.env)("SECRET_ACCESS_KEY")).map_err(to_cred_error)?; + let secret_key = (self.env)("AWS_SECRET_ACCESS_KEY") + .or_else(|_| (self.env)("SECRET_ACCESS_KEY")) + .map_err(to_cred_error)?; let session_token = (self.env)("AWS_SESSION_TOKEN").ok(); Ok(Credentials { access_key_id: access_key, secret_access_key: secret_key, session_token, expires_after: None, - provider_name: ENV_PROVIDER + provider_name: ENV_PROVIDER, }) } } @@ -52,15 +55,15 @@ impl ProvideCredentials for EnvironmentVariableCredentialsProvider { fn to_cred_error(err: VarError) -> CredentialsError { match err { VarError::NotPresent => CredentialsError::CredentialsNotLoaded, - e @ VarError::NotUnicode(_) => CredentialsError::Unhandled(Box::new(e)) + e @ VarError::NotUnicode(_) => CredentialsError::Unhandled(Box::new(e)), } } #[cfg(test)] mod test { use crate::provider::EnvironmentVariableCredentialsProvider; + use crate::{CredentialsError, ProvideCredentials}; use std::collections::HashMap; - use crate::{ProvideCredentials, CredentialsError}; #[test] fn valid_no_token() { @@ -101,7 +104,6 @@ mod test { assert_eq!(creds.session_token.unwrap(), "token"); assert_eq!(creds.access_key_id, "access"); assert_eq!(creds.secret_access_key, "secret"); - } #[test] @@ -110,8 +112,8 @@ mod test { let provider = EnvironmentVariableCredentialsProvider::for_map(env); let err = provider.credentials().expect_err("no credentials defined"); match err { - CredentialsError::Unhandled(_ ) => panic!("wrong error type"), - _ => () + CredentialsError::Unhandled(_) => panic!("wrong error type"), + _ => (), }; } diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index ceb7d03bed..e76b94eb1c 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,4 +1,4 @@ -use bytes::{Buf, Bytes}; +use bytes::Bytes; use hyper::Client as HyperClient; use operationwip::middleware::OperationError; use smithy_http::body::SdkBody; @@ -9,52 +9,8 @@ use tower::{Layer, Service, ServiceBuilder, ServiceExt}; type BoxError = Box; -#[derive(Debug)] -pub struct SdkSuccess { - pub raw: http::Response>, - pub parsed: O, -} - -#[derive(Debug)] -pub enum SdkError { - ConstructionFailure(BoxError), - DispatchFailure(BoxError), - ResponseError { - raw: http::Response>, - err: BoxError, - }, - ServiceError { - raw: http::Response>, - err: E, - }, -} - -pub fn sdk_result( - parsed: Result, - raw: http::Response, -) -> Result, SdkError> { - match parsed { - Ok(parsed) => Ok(SdkSuccess { - raw: raw.map(|b| Box::new(b) as _), - parsed, - }), - Err(err) => Err(SdkError::ServiceError { - raw: raw.map(|b| Box::new(b) as _), - err, - }), - } -} - -impl SdkError { - pub fn error(self) -> Box { - match self { - SdkError::DispatchFailure(e) => e, - SdkError::ResponseError { err, .. } => err, - SdkError::ServiceError { err, .. } => Box::new(err), - SdkError::ConstructionFailure(e) => e, - } - } -} +pub type SdkError = smithy_http::result::SdkError; +pub type SdkSuccess = smithy_http::result::SdkSuccess; pub struct Client { inner: S, @@ -62,9 +18,7 @@ pub struct Client { impl Client { pub fn new(connector: S) -> Self { - Client { - inner: connector - } + Client { inner: connector } } } @@ -84,43 +38,18 @@ impl Client { } } -fn operation_error(o: OperationError) -> SdkError - where - OE: Into, +fn operation_error(o: OperationError) -> smithy_http::result::SdkError +where + OE: Into, { match o { - OperationError::DispatchError(e) => SdkError::DispatchFailure(e.into()), - OperationError::ConstructionError(e) => SdkError::ConstructionFailure(e), - } -} - -async fn load_response( - mut response: http::Response, - handler: &O, -) -> Result, SdkError> - where - B: http_body::Body + Unpin, - B: From + Debug + 'static, - B::Error: Error + Send + Sync + 'static, - O: ParseHttpResponse>, -{ - if let Some(parsed_response) = handler.parse_unloaded(&mut response) { - return sdk_result(parsed_response, response); - } - - let body = match read_body(response.body_mut()).await { - Ok(body) => body, - Err(e) => { - return Err(SdkError::ResponseError { - raw: response.map(|b| Box::new(b) as _), - err: Box::new(e), - }); + OperationError::DispatchError(e) => { + smithy_http::result::SdkError::DispatchFailure(e.into()) } - }; - - let response = response.map(|_| Bytes::from(body)); - let parsed = handler.parse_loaded(&response); - return sdk_result(parsed, response.map(B::from)); + OperationError::ConstructionError(e) => { + smithy_http::result::SdkError::ConstructionFailure(e) + } + } } #[derive(Clone)] @@ -133,11 +62,11 @@ pub struct ParseResponseService { struct RetryStrategy {} impl -tower::retry::Policy, Response, Error> for RetryStrategy - where - R: RetryPolicy, + tower::retry::Policy, Response, Error> for RetryStrategy +where + R: RetryPolicy, { - type Future = Pin>>; + type Future = Pin>>; fn retry( &self, @@ -161,8 +90,8 @@ tower::retry::Policy, Response, Error> for Retr pub struct ParseResponseLayer; impl Layer for ParseResponseLayer - where - S: Service, +where + S: Service, { type Service = ParseResponseService; @@ -171,20 +100,19 @@ impl Layer for ParseResponseLayer } } -type BoxedResultFuture = Pin>>>; +type BoxedResultFuture = Pin>>>; impl tower::Service> for ParseResponseService - where - S: Service, Error=OperationError>, - OE: Into, - S::Future: 'static, - O: ParseHttpResponse> + 'static, - B: http_body::Body + Unpin + Debug + 'static, - B: From, - B::Error: Error + Send + Sync + 'static, +where + S: Service, Error = OperationError>, + OE: Into, + S::Future: 'static, + B: http_body::Body + Unpin + From + 'static, + B::Error: Into, + O: ParseHttpResponse> + 'static, { - type Response = SdkSuccess; - type Error = SdkError; + type Response = smithy_http::result::SdkSuccess; + type Error = smithy_http::result::SdkError; type Future = BoxedResultFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { @@ -196,7 +124,7 @@ impl tower::Service> for ParseR let resp = self.inner.call(req); let fut = async move { match resp.await { - Err(e) => Err(operation_error::(e)), + Err(e) => Err(operation_error::(e)), Ok(resp) => load_response(resp, &handler).await, } }; @@ -205,22 +133,22 @@ impl tower::Service> for ParseR } impl Client - where - S: Service, Response=http::Response> +where + S: Service, Response = http::Response> + Send + Clone + 'static, - S::Error: Into + Send + Sync + 'static, - S::Future: Send + 'static, + S::Error: Into + Send + Sync + 'static, + S::Future: Send + 'static, { /// Dispatch this request to the network /// /// For ergonomics, this does not include the raw response for successful responses. To /// access the raw response use `call_raw`. pub async fn call(&self, input: Operation) -> Result> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { self.call_raw(input).await.map(|res| res.parsed) } @@ -229,18 +157,13 @@ impl Client &self, input: Operation, ) -> Result, SdkError> - where - O: ParseHttpResponse> + Send + Clone + 'static, - Retry: RetryPolicy, SdkError> + Send + Clone + 'static, + where + O: ParseHttpResponse> + Send + Clone + 'static, + Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationPipelineService::for_stage(SignRequestStage::new()); let endpoint_resolver = OperationPipelineService::for_stage(AddEndpointStage); let inner = self.inner.clone(); - // TODO: reorder to call ready_and on the entire stack - /*let inner = inner - .ready_and() - .await - .map_err(|e| _SdkError::DispatchFailure(e.into()))?;*/ let mut svc = ServiceBuilder::new() .retry(RetryStrategy {}) .map_request(|r: Operation| r) @@ -256,7 +179,6 @@ impl Client } } -use http_body::Body; use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; @@ -264,30 +186,18 @@ use operationwip::endpoint::AddEndpointStage; use operationwip::middleware::{DispatchLayer, OperationPipelineService}; use operationwip::retry_policy::RetryPolicy; use operationwip::signing_middleware::SignRequestStage; +use smithy_http::middleware::load_response; use smithy_http::operation::Operation; -use std::fmt::Debug; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; -async fn read_body(body: B) -> Result, B::Error> { - let mut output = Vec::new(); - pin_utils::pin_mut!(body); - while let Some(buf) = body.data().await { - let mut buf = buf?; - while buf.has_remaining() { - output.extend_from_slice(buf.chunk()); - buf.advance(buf.chunk().len()) - } - } - Ok(output) -} - #[cfg(test)] mod test { use crate::{BoxError, Client}; use auth::Credentials; + use aws_sig_auth::OperationSigningConfig; use bytes::Bytes; use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; @@ -306,7 +216,6 @@ mod test { use std::sync::{mpsc, Arc}; use std::time::Duration; use std::time::UNIX_EPOCH; - use aws_sig_auth::OperationSigningConfig; #[derive(Clone)] struct TestService { @@ -326,7 +235,7 @@ mod test { impl tower::Service> for TestService { type Response = http::Response; type Error = BoxError; - type Future = Pin> + Send>>; + type Future = Pin> + Send>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -343,8 +252,8 @@ mod test { struct TestOperationParser; impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, + where + B: http_body::Body, { type Output = Result; @@ -375,22 +284,20 @@ mod test { .body(SdkBody::from("Hello")) .unwrap(), ) - .augment(|req, config| { - config.insert(Region::new("some-region")); - config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - config.insert_signing_config(OperationSigningConfig::default_config( - "some-service", - )); - use operationwip::signing_middleware::CredentialProviderExt; - config.insert_credentials_provider(Arc::new(Credentials::from_keys( - "access", "secret", None, - ))); - config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( - "http://localhost:8000", - )))); - Result::<_, ()>::Ok(req) - }) - .expect("valid request"); + .augment(|req, config| { + config.insert(Region::new("some-region")); + config.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); + config.insert_signing_config(OperationSigningConfig::default_config("some-service")); + use operationwip::signing_middleware::CredentialProviderExt; + config.insert_credentials_provider(Arc::new(Credentials::from_keys( + "access", "secret", None, + ))); + config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + "http://localhost:8000", + )))); + Result::<_, ()>::Ok(req) + }) + .expect("valid request"); let operation = Operation::new(request, TestOperationParser); diff --git a/aws/rust-runtime/aws-sig-auth/src/lib.rs b/aws/rust-runtime/aws-sig-auth/src/lib.rs index fed9787057..7c3ebabc9a 100644 --- a/aws/rust-runtime/aws-sig-auth/src/lib.rs +++ b/aws/rust-runtime/aws-sig-auth/src/lib.rs @@ -1,7 +1,7 @@ +use auth::Credentials; use std::borrow::Cow; -use std::time::SystemTime; use std::error::Error; -use auth::Credentials; +use std::time::SystemTime; #[derive(Eq, PartialEq, Clone, Copy)] pub enum SigningAlgorithm { @@ -75,8 +75,8 @@ impl HttpSigner { credentials: &Credentials, request: &mut http::Request, ) -> Result<(), SigningError> - where - B: AsRef<[u8]>, + where + B: AsRef<[u8]>, { let operation_config = &signing_config.operation_config; if operation_config.algorithm != SigningAlgorithm::SigV4 @@ -91,7 +91,7 @@ impl HttpSigner { let sigv4_creds = aws_sigv4::Credentials { access_key: credentials.access_key_id().to_string(), secret_key: credentials.secret_access_key().to_string(), - security_token: credentials.session_token().map(|s|s.to_string()), + security_token: credentials.session_token().map(|s| s.to_string()), }; let date = signing_config.request_config.request_ts; for (key, value) in aws_sigv4::sign_core( diff --git a/aws/rust-runtime/operationwip/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs index 30d092f369..65bbff7991 100644 --- a/aws/rust-runtime/operationwip/src/middleware.rs +++ b/aws/rust-runtime/operationwip/src/middleware.rs @@ -181,7 +181,7 @@ where #[cfg(test)] mod test { - use crate::middleware::{BoxError, DispatchLayer, OperationPipelineService, RequestStage}; + use crate::middleware::{DispatchLayer, OperationPipelineService, RequestStage}; use bytes::Bytes; use http::header::HeaderName; use http::{HeaderValue, Request, Response}; diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs index 44b7d78a96..d9a1355aa5 100644 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -4,9 +4,9 @@ */ use crate::middleware::RequestStage; use crate::region::RegionExt; +use auth::ProvideCredentials; use aws_sig_auth::{ - HttpSigner, HttpSigningConfig, OperationSigningConfig, RequestConfig, - SigningConfig, + HttpSigner, HttpSigningConfig, OperationSigningConfig, RequestConfig, SigningConfig, }; use http::Request; use smithy_http::operation; @@ -14,7 +14,6 @@ use smithy_http::property_bag::PropertyBag; use std::sync::Arc; use std::time::SystemTime; use tower::BoxError; -use auth::ProvideCredentials; #[derive(Clone)] pub struct SignRequestStage { diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 5c5a3c8e41..89b152b1d5 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -52,9 +52,10 @@ async fn main() -> Result<(), Box> { let config = dynamodb::Config::builder() .region("us-east-1") // To load credentials from environment variables, delete this line - .credentials_provider(auth::Credentials::from_static( + .credentials_provider(auth::Credentials::from_keys( "", "", + None )) // To use real DynamoDB, delete this line: .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static( @@ -106,7 +107,7 @@ async fn main() -> Result<(), Box> { output.table_names.unwrap_or_default() ); } - Err(e) => panic!("err: {:?}", e.error()), + Err(e) => panic!("err: {:?}", e.source()), }; Ok(()) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index 001f70609f..301e64f014 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -73,8 +73,6 @@ class OperationInputBuilderGenerator( val returnType = "#T<#{T}, $retryType>".letIf(fallibleBuilder) { "Result<$it, String>" } val outputSymbol = symbolProvider.toSymbol(shape) val operationT = RuntimeType.operation(symbolProvider.config().runtimeConfig) - val operationModule = RuntimeType.operationModule(symbolProvider.config().runtimeConfig) - val sdkBody = RuntimeType.sdkBody(symbolProvider.config().runtimeConfig) implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) implBlockWriter.rustBlock( diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt index 5ab3010dbc..c0e0c4505c 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/HttpProtocolGenerator.kt @@ -87,7 +87,6 @@ abstract class HttpProtocolGenerator( // pub fn builder() -> ... { } builderGenerator.renderConvenienceMethod(this) } - extras(operationWriter, operationShape) val operationName = symbolProvider.toSymbol(operationShape).name operationWriter.documentShape(operationShape, model) Derives(setOf(RuntimeType.Std("clone::Clone"))).render(operationWriter) @@ -176,6 +175,4 @@ abstract class HttpProtocolGenerator( operationShape: OperationShape, inputShape: StructureShape ) - - open fun extras(moduleWriter: RustWriter, operationShape: OperationShape) {} } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt index 99d72a586f..70b7dcf531 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson10.kt @@ -290,19 +290,4 @@ class BasicAwsJsonGenerator( } write("_ => #T::unhandled(generic)", errorSymbol) } - - override fun extras(moduleWriter: RustWriter, operationShape: OperationShape) { - val outputSymbol = symbolProvider.toSymbol(operationShape.outputShape(model)) - moduleWriter.rustTemplate( - """ - impl #{parse_strict} for ${symbolProvider.toSymbol(operationShape).name} { - type Output = Result<#{output}, #{error}>; - fn parse(&self, response: &#{response}<#{bytes}>) -> Self::Output { - self.parse_response(response) - } - } - """, - "parse_strict" to RuntimeType.ParseStrict(symbolProvider.config().runtimeConfig), "output" to outputSymbol, "error" to operationShape.errorSymbol(symbolProvider), "response" to RuntimeType.Http("Response"), "bytes" to RuntimeType.Bytes - ) - } } diff --git a/rust-runtime/smithy-http/src/result.rs b/rust-runtime/smithy-http/src/result.rs index bfa8e76b31..0c887ecb6e 100644 --- a/rust-runtime/smithy-http/src/result.rs +++ b/rust-runtime/smithy-http/src/result.rs @@ -4,9 +4,10 @@ */ use std::error::Error; -use std::fmt::Debug; +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; -type BoxError = Box; +type BoxError = Box; /// Body type when a response is returned. Currently, the only use case is introspecting errors /// so it is simply `Debug`. This is an area of potential design iteration. @@ -30,7 +31,7 @@ pub struct SdkSuccess { /// Failing Sdk Result /// -/// Typically, transport implementations will type alias (or entirely wrap / transform) this type +/// Typically, transport implementations will type alias (or wrap / transform) this type /// by specifying a concrete body implementation: /// ```rust /// # mod hyper { @@ -57,3 +58,28 @@ pub enum SdkError { /// An error response was received from the service ServiceError { raw: http::Response, err: E }, } + +impl Display for SdkError +where + E: Error, + B: Debug, +{ + fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result { + unimplemented!() + } +} + +impl Error for SdkError +where + E: Error + 'static, + B: Debug, +{ + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + SdkError::ConstructionFailure(err) + | SdkError::DispatchFailure(err) + | SdkError::ResponseError { err, .. } => Some(err.as_ref()), + SdkError::ServiceError { err, .. } => Some(err), + } + } +} From de2be35a9be1d40aa5bf4b0fd8424d8cd7a20e67 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 8 Feb 2021 09:12:18 -0500 Subject: [PATCH 44/50] More cleanups --- aws/rust-runtime/operationwip/src/endpoint.rs | 4 ++-- aws/rust-runtime/operationwip/src/middleware.rs | 13 +++++-------- .../operationwip/src/signing_middleware.rs | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/aws/rust-runtime/operationwip/src/endpoint.rs b/aws/rust-runtime/operationwip/src/endpoint.rs index dbf40dea2d..12fe63d972 100644 --- a/aws/rust-runtime/operationwip/src/endpoint.rs +++ b/aws/rust-runtime/operationwip/src/endpoint.rs @@ -8,11 +8,11 @@ use std::str::FromStr; use http::uri::Uri; -use crate::middleware::RequestStage; use http::header::HOST; use smithy_http::operation; use smithy_http::property_bag::PropertyBag; use std::sync::Arc; +use smithy_http::middleware::MapRequest; pub struct StaticEndpoint(http::Uri); @@ -95,7 +95,7 @@ impl EndpointProviderExt for PropertyBag { #[derive(Clone, Copy)] /// Set the endpoint for a request based on the endpoint config pub struct AddEndpointStage; -impl RequestStage for AddEndpointStage { +impl MapRequest for AddEndpointStage { type Error = String; fn apply(&self, request: operation::Request) -> Result { request.augment(|mut request, extensions| { diff --git a/aws/rust-runtime/operationwip/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs index 65bbff7991..163ae77d49 100644 --- a/aws/rust-runtime/operationwip/src/middleware.rs +++ b/aws/rust-runtime/operationwip/src/middleware.rs @@ -12,11 +12,7 @@ type BoxError = Box; use pin_project::pin_project; use smithy_http::body::SdkBody; use smithy_http::operation; - -pub trait RequestStage { - type Error: Into; - fn apply(&self, request: operation::Request) -> Result; -} +use smithy_http::middleware::MapRequest; #[derive(Clone)] pub struct OperationRequestMiddlewareService { @@ -75,7 +71,7 @@ where impl Service for OperationRequestMiddlewareService where S: Service, - M: RequestStage, + M: MapRequest, S::Error: RequestConstructionErr, { type Response = S::Response; @@ -181,7 +177,7 @@ where #[cfg(test)] mod test { - use crate::middleware::{DispatchLayer, OperationPipelineService, RequestStage}; + use crate::middleware::{DispatchLayer, OperationPipelineService}; use bytes::Bytes; use http::header::HeaderName; use http::{HeaderValue, Request, Response}; @@ -193,6 +189,7 @@ mod test { use std::convert::Infallible; use tower::service_fn; use tower::{Layer, Service}; + use smithy_http::middleware::MapRequest; struct TestOperationParser; @@ -215,7 +212,7 @@ mod test { async fn middleware_test() { #[derive(Clone)] struct AddHeader(String, String); - impl RequestStage for AddHeader { + impl MapRequest for AddHeader { type Error = Infallible; fn apply( &self, diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs index d9a1355aa5..8f160f5a1b 100644 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -2,7 +2,6 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ -use crate::middleware::RequestStage; use crate::region::RegionExt; use auth::ProvideCredentials; use aws_sig_auth::{ @@ -14,6 +13,7 @@ use smithy_http::property_bag::PropertyBag; use std::sync::Arc; use std::time::SystemTime; use tower::BoxError; +use smithy_http::middleware::MapRequest; #[derive(Clone)] pub struct SignRequestStage { @@ -76,7 +76,7 @@ impl CredentialProviderExt for PropertyBag { } } -impl RequestStage for SignRequestStage { +impl MapRequest for SignRequestStage { type Error = BoxError; fn apply(&self, request: operation::Request) -> Result { request.augment(|request, config| { From 20e54665808a60fce38fc0811e6abf61e01a541e Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 10 Feb 2021 18:25:33 -0500 Subject: [PATCH 45/50] Get working KMS client --- aws/rust-runtime/aws-hyper/Cargo.toml | 2 +- aws/rust-runtime/aws-hyper/src/lib.rs | 2 +- aws/rust-runtime/aws-sig-auth/Cargo.toml | 2 +- aws/rust-runtime/aws-sig-auth/src/lib.rs | 2 +- aws/rust-runtime/operationwip/Cargo.toml | 2 +- .../operationwip/src/signing_middleware.rs | 2 +- .../rustsdk/CredentialProviderConfig.kt | 6 ++--- aws/sdk/build.gradle.kts | 4 +-- aws/sdk/examples/dynamo-helloworld/Cargo.toml | 3 ++- .../examples/dynamo-helloworld/src/main.rs | 27 ------------------- aws/sdk/integration-tests/tests/dynamodb.rs | 2 +- 11 files changed, 14 insertions(+), 40 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index fd1c498cc9..99b80a7f28 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -12,7 +12,7 @@ tower = { version = "0.4.2", features = ["retry", "buffer"] } operationwip = { path = "../operationwip" } middleware-tracing = { path = "../middleware-tracing" } hyper-tls = "0.5.0" -auth = { path = "../auth" } +aws-auth = { path = "../aws-auth" } aws-sig-auth = { path = "../aws-sig-auth" } http = "0.2.3" bytes = "1" diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index e76b94eb1c..72bfbd8e00 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -196,7 +196,7 @@ use std::time::Duration; #[cfg(test)] mod test { use crate::{BoxError, Client}; - use auth::Credentials; + use aws_auth::Credentials; use aws_sig_auth::OperationSigningConfig; use bytes::Bytes; use http::header::AUTHORIZATION; diff --git a/aws/rust-runtime/aws-sig-auth/Cargo.toml b/aws/rust-runtime/aws-sig-auth/Cargo.toml index a3f76c6ace..2aa55b1645 100644 --- a/aws/rust-runtime/aws-sig-auth/Cargo.toml +++ b/aws/rust-runtime/aws-sig-auth/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] http = "0.2.2" aws-sigv4 = { git = "https://github.com/rcoh/sigv4", rev = "05f90abc02a868cb570ed3006d950947cc0898b0" } -auth = { path = "../auth" } +aws-auth = { path = "../aws-auth" } [dev-dependencies] tokio = { version = "1", features = ["full"]} diff --git a/aws/rust-runtime/aws-sig-auth/src/lib.rs b/aws/rust-runtime/aws-sig-auth/src/lib.rs index 7c3ebabc9a..027b0daa23 100644 --- a/aws/rust-runtime/aws-sig-auth/src/lib.rs +++ b/aws/rust-runtime/aws-sig-auth/src/lib.rs @@ -1,4 +1,4 @@ -use auth::Credentials; +use aws_auth::Credentials; use std::borrow::Cow; use std::error::Error; use std::time::SystemTime; diff --git a/aws/rust-runtime/operationwip/Cargo.toml b/aws/rust-runtime/operationwip/Cargo.toml index 8389b9aad5..5bd73e284c 100644 --- a/aws/rust-runtime/operationwip/Cargo.toml +++ b/aws/rust-runtime/operationwip/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -auth = { path = "../auth" } +aws-auth = { path = "../aws-auth" } aws-sig-auth = { path = "../aws-sig-auth" } http = "0.2.3" bytes = "1" diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs index 8f160f5a1b..287f46a5d5 100644 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0. */ use crate::region::RegionExt; -use auth::ProvideCredentials; +use aws_auth::ProvideCredentials; use aws_sig_auth::{ HttpSigner, HttpSigningConfig, OperationSigningConfig, RequestConfig, SigningConfig, }; diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt index 86e5c2caf9..2beefe1925 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfig.kt @@ -43,6 +43,6 @@ class CredentialProviderConfig : ConfigCustomization() { } } -val Auth = CargoDependency("auth", Local("../")) -val CredentialsProvider = RuntimeType("ProvideCredentials", Auth, "auth") -val DefaultProvider = RuntimeType("default_provider", Auth, "auth") +val Auth = CargoDependency("aws-auth", Local("../")) +val CredentialsProvider = RuntimeType("ProvideCredentials", Auth, "aws_auth") +val DefaultProvider = RuntimeType("default_provider", Auth, "aws_auth") diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index 4dbb7023f2..485a1c7046 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -22,8 +22,8 @@ val sdkOutputDir = buildDir.resolve("aws-sdk") val awsServices = discoverServices() // TODO: smithy-http should be removed val runtimeModules = listOf("smithy-types", "smithy-http") -val examples = listOf("dynamo-helloworld") -val awsModules = listOf("auth", "operationwip", "aws-hyper", "middleware-tracing", "aws-sig-auth") +val examples = listOf("dynamo-helloworld", "kms-helloworld") +val awsModules = listOf("aws-auth", "operationwip", "aws-hyper", "middleware-tracing", "aws-sig-auth") buildscript { val smithyVersion: String by project diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.toml b/aws/sdk/examples/dynamo-helloworld/Cargo.toml index 855746a4e6..4064dcd7ea 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.toml +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.toml @@ -8,9 +8,10 @@ edition = "2018" [dependencies] dynamodb = { version = "0.0.1", path = "../../build/aws-sdk/dynamodb" } +kms = { path = "../../build/aws-sdk/kms" } aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } operationwip = { path = "../../build/aws-sdk/operationwip" } -auth = { path = "../../build/aws-sdk/auth" } +aws-auth = { path = "../../build/aws-sdk/aws-auth" } tokio = { version = "1", features = ["full"] } http = "0.2.3" env_logger = "0.8.2" diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 89b152b1d5..8acbe90cbc 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -19,33 +19,6 @@ use operationwip::endpoint::StaticEndpoint; use operationwip::retry_policy::{RetryPolicy, RetryType}; use tokio::time::Duration; -#[derive(Clone)] -struct RetryIfNoTables; -impl RetryPolicy, SdkError> for RetryIfNoTables { - fn should_retry( - &self, - input: Result<&SdkSuccess, &SdkError>, - ) -> Option { - match input { - Ok(list_tables) => { - if list_tables - .parsed - .table_names - .as_ref() - .map(|t| t.len()) - .unwrap_or_default() - == 0 - { - Some(RetryType::Explicit(Duration::new(5, 0))) - } else { - None - } - } - _ => None, - } - } -} - #[tokio::main] async fn main() -> Result<(), Box> { env_logger::init_from_env(Env::default().default_filter_or("info")); diff --git a/aws/sdk/integration-tests/tests/dynamodb.rs b/aws/sdk/integration-tests/tests/dynamodb.rs index 3b79fc92c1..4be6f90520 100644 --- a/aws/sdk/integration-tests/tests/dynamodb.rs +++ b/aws/sdk/integration-tests/tests/dynamodb.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0. */ -use auth::Credentials; +use aws_auth::Credentials; use bytes::Bytes; use dynamodb::operation::ListTables; use smithy_http::body::SdkBody; From 8fddd4b47ed451bb5ce09f2fa4999c996bd9f6c5 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 10 Feb 2021 18:37:04 -0500 Subject: [PATCH 46/50] Add KMS example --- .../{dynamo-helloworld => }/.gitignore | 0 aws/sdk/examples/dynamo-helloworld/Cargo.lock | 1355 +++++++++++++++++ aws/sdk/examples/kms-helloworld/Cargo.lock | 1254 +++++++++++++++ aws/sdk/examples/kms-helloworld/Cargo.toml | 14 + aws/sdk/examples/kms-helloworld/src/main.rs | 17 + 5 files changed, 2640 insertions(+) rename aws/sdk/examples/{dynamo-helloworld => }/.gitignore (100%) create mode 100644 aws/sdk/examples/dynamo-helloworld/Cargo.lock create mode 100644 aws/sdk/examples/kms-helloworld/Cargo.lock create mode 100644 aws/sdk/examples/kms-helloworld/Cargo.toml create mode 100644 aws/sdk/examples/kms-helloworld/src/main.rs diff --git a/aws/sdk/examples/dynamo-helloworld/.gitignore b/aws/sdk/examples/.gitignore similarity index 100% rename from aws/sdk/examples/dynamo-helloworld/.gitignore rename to aws/sdk/examples/.gitignore diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock new file mode 100644 index 0000000000..77baa85dbb --- /dev/null +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -0,0 +1,1355 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "async-stream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3670df70cbc01729f901f94c887814b3c68db038aad1329a418bae178bc5295c" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3548b8efc9f8e8a5a0a2808c5bd8451a9031b9e5b879a79590304ae928b0a70" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "aws-auth" +version = "0.1.0" + +[[package]] +name = "aws-hyper" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "http-body", + "hyper", + "hyper-tls", + "middleware-tracing", + "operationwip", + "pin-utils", + "smithy-http", + "tokio", + "tower", +] + +[[package]] +name = "aws-sig-auth" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-sigv4", + "http", +] + +[[package]] +name = "aws-sigv4" +version = "0.0.1" +source = "git+https://github.com/rcoh/sigv4?rev=05f90abc02a868cb570ed3006d950947cc0898b0#05f90abc02a868cb570ed3006d950947cc0898b0" +dependencies = [ + "bytes", + "chrono", + "hex", + "http", + "http-body", + "ring", + "serde", + "serde_urlencoded", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bumpalo" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f07aa6688c702439a1be0307b6a94dffe1168569e45b9500c1372bc580740d59" + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + +[[package]] +name = "cc" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "dynamo-helloworld" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-hyper", + "dynamodb", + "env_logger", + "http", + "kms", + "operationwip", + "tokio", +] + +[[package]] +name = "dynamodb" +version = "0.0.1" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "operationwip", + "rand 0.7.3", + "serde", + "serde_json", + "smithy-http", + "smithy-types", +] + +[[package]] +name = "env_logger" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" + +[[package]] +name = "futures-sink" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" + +[[package]] +name = "futures-task" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" + +[[package]] +name = "futures-util" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.1+wasi-snapshot-preview1", +] + +[[package]] +name = "h2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", + "tracing-futures", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + +[[package]] +name = "http" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.4", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "indexmap" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "js-sys" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kms" +version = "0.0.1" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "operationwip", + "serde", + "serde_json", + "smithy-http", + "smithy-types", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0c4e9c72ee9d69b767adebc5f4788462a3b45624acd919475c92597bcaf4f" + +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "middleware-tracing" +version = "0.1.0" +dependencies = [ + "http", + "tower", + "tracing", + "tracing-futures", +] + +[[package]] +name = "mio" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +dependencies = [ + "socket2", + "winapi", +] + +[[package]] +name = "native-tls" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" + +[[package]] +name = "openssl" +version = "0.10.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "operationwip" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "http-body", + "pin-project 1.0.4", + "smithy-http", + "tower", +] + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +dependencies = [ + "pin-project-internal 0.4.27", +] + +[[package]] +name = "pin-project" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" +dependencies = [ + "pin-project-internal 1.0.4", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.0", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom 0.2.2", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "smithy-http" +version = "0.0.1" +dependencies = [ + "bytes", + "http", + "http-body", + "smithy-types", +] + +[[package]] +name = "smithy-types" +version = "0.0.1" +dependencies = [ + "chrono", +] + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand 0.8.3", + "redox_syscall 0.2.4", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tokio" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8efab2086f17abcddb8f756117665c958feee6b2e39974c2f1600592ab3a4195" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb971a26599ffd28066d387f109746df178eff14d5ea1e235015c5601967a4b" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tower" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd7b451959622e21de79261673d658a0944b835012c58c51878ea55957fb51a" +dependencies = [ + "futures-core", + "futures-util", + "pin-project 1.0.4", + "tokio", + "tokio-stream", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" +dependencies = [ + "pin-project 0.4.27", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" + +[[package]] +name = "wasm-bindgen" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" + +[[package]] +name = "web-sys" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/aws/sdk/examples/kms-helloworld/Cargo.lock b/aws/sdk/examples/kms-helloworld/Cargo.lock new file mode 100644 index 0000000000..6c774197ae --- /dev/null +++ b/aws/sdk/examples/kms-helloworld/Cargo.lock @@ -0,0 +1,1254 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "aws-auth" +version = "0.1.0" + +[[package]] +name = "aws-hyper" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "http-body", + "hyper", + "hyper-tls", + "middleware-tracing", + "operationwip", + "pin-utils", + "smithy-http", + "tokio", + "tower", +] + +[[package]] +name = "aws-sig-auth" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-sigv4", + "http", +] + +[[package]] +name = "aws-sigv4" +version = "0.0.1" +source = "git+https://github.com/rcoh/sigv4?rev=05f90abc02a868cb570ed3006d950947cc0898b0#05f90abc02a868cb570ed3006d950947cc0898b0" +dependencies = [ + "bytes", + "chrono", + "hex", + "http", + "http-body", + "ring", + "serde", + "serde_urlencoded", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bumpalo" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + +[[package]] +name = "cc" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "env_logger" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" + +[[package]] +name = "futures-sink" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" + +[[package]] +name = "futures-task" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" + +[[package]] +name = "futures-util" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", + "tracing-futures", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + +[[package]] +name = "http" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "httparse" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" + +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.5", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "indexmap" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "js-sys" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kms" +version = "0.0.1" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "operationwip", + "serde", + "serde_json", + "smithy-http", + "smithy-types", +] + +[[package]] +name = "kms-helloworld" +version = "0.1.0" +dependencies = [ + "aws-hyper", + "env_logger", + "kms", + "tokio", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "middleware-tracing" +version = "0.1.0" +dependencies = [ + "http", + "tower", + "tracing", + "tracing-futures", +] + +[[package]] +name = "mio" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +dependencies = [ + "socket2", + "winapi", +] + +[[package]] +name = "native-tls" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" + +[[package]] +name = "openssl" +version = "0.10.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "operationwip" +version = "0.1.0" +dependencies = [ + "aws-auth", + "aws-sig-auth", + "bytes", + "http", + "http-body", + "pin-project 1.0.5", + "smithy-http", + "tower", +] + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +dependencies = [ + "pin-project-internal 0.4.27", +] + +[[package]] +name = "pin-project" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" +dependencies = [ + "pin-project-internal 1.0.5", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "smithy-http" +version = "0.0.1" +dependencies = [ + "bytes", + "http", + "http-body", + "smithy-types", +] + +[[package]] +name = "smithy-types" +version = "0.0.1" +dependencies = [ + "chrono", +] + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall 0.2.4", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tokio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1981ad97df782ab506a1f43bf82c967326960d278acf3bf8279809648c3ff3ea" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd7b451959622e21de79261673d658a0944b835012c58c51878ea55957fb51a" +dependencies = [ + "futures-core", + "futures-util", + "pin-project 1.0.5", + "tokio", + "tokio-stream", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d40a22fd029e33300d8d89a5cc8ffce18bb7c587662f54629e94c9de5487f3" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f080ea7e4107844ef4766459426fa2d5c1ada2e47edba05dc7fa99d9629f47" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" +dependencies = [ + "pin-project 0.4.27", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" + +[[package]] +name = "web-sys" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/aws/sdk/examples/kms-helloworld/Cargo.toml b/aws/sdk/examples/kms-helloworld/Cargo.toml new file mode 100644 index 0000000000..0292c4c922 --- /dev/null +++ b/aws/sdk/examples/kms-helloworld/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "kms-helloworld" +version = "0.1.0" +authors = ["Russell Cohen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +kms = { path = "../../build/aws-sdk/kms" } +aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } +tokio = { version = "1", features = ["full"]} +# optional +env_logger = "0.8.2" diff --git a/aws/sdk/examples/kms-helloworld/src/main.rs b/aws/sdk/examples/kms-helloworld/src/main.rs new file mode 100644 index 0000000000..b39c6500d6 --- /dev/null +++ b/aws/sdk/examples/kms-helloworld/src/main.rs @@ -0,0 +1,17 @@ +use kms::operation::GenerateRandom; +use env_logger::Env; + +#[tokio::main] +async fn main() { + env_logger::init_from_env(Env::default().default_filter_or("info")); + let config = kms::Config::builder() + .region("us-east-1") + // creds loaded from environment variables, or they can be hard coded. Other credential providers not supported + .build(); + let client = aws_hyper::Client::default().with_tracing(); + let data = client + .call(GenerateRandom::builder().number_of_bytes(64).build(&config)) + .await + .expect("failed to generate random"); + println!("{:?}", data); +} From bbd5bb1546887bbb450cf892293c6a1557a059d9 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 12 Feb 2021 11:12:20 -0500 Subject: [PATCH 47/50] get the dynamo test compiling again --- aws/rust-runtime/aws-endpoint/src/lib.rs | 1 + aws/rust-runtime/aws-hyper/Cargo.toml | 1 + aws/rust-runtime/aws-hyper/src/lib.rs | 5 +- aws/rust-runtime/aws-types/src/lib.rs | 26 ++++ aws/rust-runtime/operationwip/Cargo.toml | 1 + aws/rust-runtime/operationwip/src/endpoint.rs | 145 ------------------ aws/rust-runtime/operationwip/src/lib.rs | 2 - aws/rust-runtime/operationwip/src/region.rs | 83 ---------- .../operationwip/src/signing_middleware.rs | 7 +- .../smithy/rustsdk/AwsCodegenDecorator.kt | 3 +- .../amazon/smithy/rustsdk/EndpointConfig.kt | 25 +-- .../amazon/smithy/rustsdk/RegionConfig.kt | 17 +- .../amazon/smithy/rustsdk/SigningConfig.kt | 6 +- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 108 +++++-------- aws/sdk/examples/dynamo-helloworld/Cargo.toml | 1 + .../examples/dynamo-helloworld/src/main.rs | 10 +- aws/sdk/examples/kms-helloworld/Cargo.lock | 20 +++ 17 files changed, 131 insertions(+), 330 deletions(-) delete mode 100644 aws/rust-runtime/operationwip/src/endpoint.rs delete mode 100644 aws/rust-runtime/operationwip/src/region.rs diff --git a/aws/rust-runtime/aws-endpoint/src/lib.rs b/aws/rust-runtime/aws-endpoint/src/lib.rs index d49ef0c3bf..20f4efccf3 100644 --- a/aws/rust-runtime/aws-endpoint/src/lib.rs +++ b/aws/rust-runtime/aws-endpoint/src/lib.rs @@ -118,6 +118,7 @@ pub fn set_endpoint_resolver(provider: AwsEndpointResolver, config: &mut Propert /// 3. Apply the endpoint to the URI in the request /// 4. Set the `SigningRegion` and `SigningService` in the property bag to drive downstream /// signing middleware. +#[derive(Clone)] pub struct AwsEndpointStage; #[derive(Debug)] diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 99b80a7f28..abe69264e7 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -14,6 +14,7 @@ middleware-tracing = { path = "../middleware-tracing" } hyper-tls = "0.5.0" aws-auth = { path = "../aws-auth" } aws-sig-auth = { path = "../aws-sig-auth" } +aws-endpoint = { path = "../aws-endpoint" } http = "0.2.3" bytes = "1" http-body = "0.4.0" diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 72bfbd8e00..264ad24ac5 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -162,7 +162,7 @@ where Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { let signer = OperationPipelineService::for_stage(SignRequestStage::new()); - let endpoint_resolver = OperationPipelineService::for_stage(AddEndpointStage); + let endpoint_resolver = OperationPipelineService::for_stage(AwsEndpointStage); let inner = self.inner.clone(); let mut svc = ServiceBuilder::new() .retry(RetryStrategy {}) @@ -182,7 +182,6 @@ where use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; -use operationwip::endpoint::AddEndpointStage; use operationwip::middleware::{DispatchLayer, OperationPipelineService}; use operationwip::retry_policy::RetryPolicy; use operationwip::signing_middleware::SignRequestStage; @@ -192,6 +191,7 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; +use aws_endpoint::AwsEndpointStage; #[cfg(test)] mod test { @@ -201,7 +201,6 @@ mod test { use bytes::Bytes; use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; - use operationwip::endpoint::{EndpointProviderExt, StaticEndpoint}; use operationwip::region::Region; use operationwip::signing_middleware::SigningConfigExt; use pin_utils::core_reexport::task::{Context, Poll}; diff --git a/aws/rust-runtime/aws-types/src/lib.rs b/aws/rust-runtime/aws-types/src/lib.rs index cedfd81dcf..487d843ca6 100644 --- a/aws/rust-runtime/aws-types/src/lib.rs +++ b/aws/rust-runtime/aws-types/src/lib.rs @@ -23,6 +23,32 @@ impl Region { } } +pub mod region { + use crate::Region; + + pub trait ProvideRegion { + fn region(&self) -> Option; + } + + impl ProvideRegion for &str { + fn region(&self) -> Option { + Some(Region::new(*self)) + } + } + + struct RegionEnvironment; + + impl ProvideRegion for RegionEnvironment { + fn region(&self) -> Option { + std::env::var("AWS_DEFAULT_REGION").map(Region::new).ok() + } + } + + pub fn default_provider() -> impl ProvideRegion { + RegionEnvironment + } +} + /// The region to use when signing requests /// /// Generally, user code will not need to interact with `SigningRegion`. See `[Region](crate::Region)`. diff --git a/aws/rust-runtime/operationwip/Cargo.toml b/aws/rust-runtime/operationwip/Cargo.toml index 5bd73e284c..a677f3699e 100644 --- a/aws/rust-runtime/operationwip/Cargo.toml +++ b/aws/rust-runtime/operationwip/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] aws-auth = { path = "../aws-auth" } aws-sig-auth = { path = "../aws-sig-auth" } +aws-types = { path = "../aws-types" } http = "0.2.3" bytes = "1" tower = { version = "0.4.2", features = ["util"] } diff --git a/aws/rust-runtime/operationwip/src/endpoint.rs b/aws/rust-runtime/operationwip/src/endpoint.rs deleted file mode 100644 index 12fe63d972..0000000000 --- a/aws/rust-runtime/operationwip/src/endpoint.rs +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -use core::convert::AsRef; -use std::str::FromStr; - -use http::uri::Uri; - -use http::header::HOST; -use smithy_http::operation; -use smithy_http::property_bag::PropertyBag; -use std::sync::Arc; -use smithy_http::middleware::MapRequest; - -pub struct StaticEndpoint(http::Uri); - -impl StaticEndpoint { - pub fn uri(&self) -> &Uri { - &self.0 - } - pub fn from_service_region(svc: impl AsRef, region: impl AsRef) -> Self { - StaticEndpoint( - Uri::from_str(&format!( - "https://{}.{}.amazonaws.com", - svc.as_ref(), - region.as_ref() - )) - .unwrap(), - ) - } - - pub fn from_uri(uri: Uri) -> Self { - StaticEndpoint(uri) - } - - pub fn apply(&self, base_uri: &Uri) -> Uri { - let parts = self.0.clone().into_parts(); - - Uri::builder() - .authority(parts.authority.expect("base uri must have an authority")) - .scheme(parts.scheme.expect("base uri must have scheme")) - .path_and_query(base_uri.path_and_query().unwrap().clone()) - .build() - .expect("valid uri") - } -} - -pub trait ProvideEndpoint: Send + Sync { - fn set_endpoint(&self, request_uri: &mut Uri); -} - -impl ProvideEndpoint for StaticEndpoint { - fn set_endpoint(&self, request_uri: &mut Uri) { - let new_uri = self.apply(request_uri); - *request_uri = new_uri; - } -} - -/* -impl OperationMiddleware for T -where - T: ProvideEndpoint, -{ - fn apply(&self, mut request: operation::Request) -> Result { - request.augment(|request, config| { - self.set_endpoint(&mut request.); - }) - } -}*/ - -pub trait EndpointProviderExt { - fn endpoint_provider(&self) -> Option<&Arc>; - fn insert_endpoint_provider( - &mut self, - provider: Arc, - ) -> Option>; -} - -impl EndpointProviderExt for PropertyBag { - fn endpoint_provider(&self) -> Option<&Arc> { - self.get() - } - - fn insert_endpoint_provider( - &mut self, - provider: Arc, - ) -> Option> { - self.insert(provider) - } -} - -// TODO: this should probably move to a collection of middlewares -#[derive(Clone, Copy)] -/// Set the endpoint for a request based on the endpoint config -pub struct AddEndpointStage; -impl MapRequest for AddEndpointStage { - type Error = String; - fn apply(&self, request: operation::Request) -> Result { - request.augment(|mut request, extensions| { - let endpoint_provider: &Arc = extensions - .endpoint_provider() - .ok_or("missing endpoint provider")?; - endpoint_provider.set_endpoint(&mut request.uri_mut()); - let uri = request.uri().host().unwrap().to_string(); - request.headers_mut().append( - HOST, - uri.parse().expect("host should be valid header value"), - ); - Ok(request) - }) - } -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - - use http::Uri; - - use crate::endpoint::StaticEndpoint; - - #[test] - fn endpoint_from_svc() { - let endpoint = StaticEndpoint::from_service_region("dynamodb", "us-west-2"); - assert_eq!( - endpoint.uri().to_string(), - "https://dynamodb.us-west-2.amazonaws.com/" - ); - } - - #[test] - fn properly_update_uri() { - let uri = Uri::builder() - .path_and_query("/get?k=123&v=456") - .build() - .unwrap(); - let endpoint = StaticEndpoint::from_uri(Uri::from_str("http://localhost:8080/").unwrap()); - assert_eq!( - endpoint.apply(&uri).to_string(), - "http://localhost:8080/get?k=123&v=456" - ); - } -} diff --git a/aws/rust-runtime/operationwip/src/lib.rs b/aws/rust-runtime/operationwip/src/lib.rs index bda0d0ce3a..7619ff71fb 100644 --- a/aws/rust-runtime/operationwip/src/lib.rs +++ b/aws/rust-runtime/operationwip/src/lib.rs @@ -1,5 +1,3 @@ -pub mod endpoint; pub mod middleware; -pub mod region; pub mod retry_policy; pub mod signing_middleware; diff --git a/aws/rust-runtime/operationwip/src/region.rs b/aws/rust-runtime/operationwip/src/region.rs deleted file mode 100644 index d22e5145aa..0000000000 --- a/aws/rust-runtime/operationwip/src/region.rs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -use smithy_http::property_bag::PropertyBag; - -#[derive(Clone)] -pub struct Region(String); - -impl AsRef for Region { - fn as_ref(&self) -> &str { - &self.0 - } -} -impl Region { - pub fn new(region: impl Into) -> Self { - Region(region.into()) - } -} - -pub trait ProvideRegion { - fn region(&self) -> Option; -} - -impl ProvideRegion for &str { - fn region(&self) -> Option { - Some(Region((*self).into())) - } -} - -struct RegionEnvironment; - -impl ProvideRegion for RegionEnvironment { - fn region(&self) -> Option { - std::env::var("AWS_DEFAULT_REGION").map(Region::new).ok() - } -} - -pub fn default_provider() -> impl ProvideRegion { - RegionEnvironment -} - -pub struct SigningRegion(String); - -impl SigningRegion { - pub fn new(region: impl Into) -> Self { - SigningRegion(region.into()) - } -} - -pub trait RegionExt { - fn request_region(&self) -> Option<&str>; - fn signing_region(&self) -> Option<&str>; -} - -impl RegionExt for PropertyBag { - fn request_region(&self) -> Option<&str> { - self.get::().map(|reg| reg.0.as_str()) - } - - fn signing_region(&self) -> Option<&str> { - self.get::() - .map(|reg| reg.0.as_str()) - .or_else(|| self.request_region()) - } -} - -#[cfg(test)] -mod test { - use crate::region::{Region, RegionExt, SigningRegion}; - use smithy_http::property_bag::PropertyBag; - - #[test] - fn signing_region_fallback() { - let mut property_bag = PropertyBag::new(); - property_bag.insert(Region::new("aws-global")); - assert_eq!(property_bag.signing_region(), Some("aws-global")); - - property_bag.insert(SigningRegion::new("us-east-1")); - assert_eq!(property_bag.signing_region(), Some("us-east-1")) - } -} diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs index 287f46a5d5..50f21470d9 100644 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ b/aws/rust-runtime/operationwip/src/signing_middleware.rs @@ -2,7 +2,6 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ -use crate::region::RegionExt; use aws_auth::ProvideCredentials; use aws_sig_auth::{ HttpSigner, HttpSigningConfig, OperationSigningConfig, RequestConfig, SigningConfig, @@ -14,6 +13,7 @@ use std::sync::Arc; use std::time::SystemTime; use tower::BoxError; use smithy_http::middleware::MapRequest; +use aws_types::SigningRegion; #[derive(Clone)] pub struct SignRequestStage { @@ -88,10 +88,9 @@ impl MapRequest for SignRequestStage { Ok(creds) => creds, Err(e) => return Err(e.into()), }; - let region = config - .signing_region() + let region = config.get::() .ok_or("Can't sign; No region defined")? - .to_string(); + .as_ref().to_string(); let request_config = RequestConfig { request_ts: config .get::() 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 8e717706c8..737467c299 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 @@ -20,7 +20,6 @@ class AwsCodegenDecorator : RustCodegenDecorator { baseCustomizations: List ): List { val awsCustomizations = mutableListOf() - awsCustomizations += CredentialProviderConfig() awsCustomizations += RegionConfig(protocolConfig.runtimeConfig) awsCustomizations += EndpointConfigCustomization(protocolConfig) protocolConfig.serviceShape.getTrait(SigV4Trait::class.java).map { trait -> @@ -34,6 +33,6 @@ class AwsCodegenDecorator : RustCodegenDecorator { operation: OperationShape, baseCustomizations: List ): List { - return listOf(SigV4SigningPlugin(operation), EndpointConfigPlugin(operation), RegionConfigPlugin(operation)) + baseCustomizations + return listOf(SigV4SigningPlugin(operation, protocolConfig.runtimeConfig), EndpointConfigPlugin(protocolConfig.runtimeConfig, operation), RegionConfigPlugin(operation)) + baseCustomizations } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt index 353e63bd93..b1faca54ba 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointConfig.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.aws.traits.ServiceTrait import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.EndpointTrait import software.amazon.smithy.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.Local import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.writable @@ -43,31 +44,37 @@ class EndpointConfigCustomization(private val protocolConfig: ProtocolConfig) : ServiceConfig.BuilderBuild -> rust( """endpoint_provider: self.endpoint_provider.unwrap_or_else(|| ::std::sync::Arc::new( - #T::from_service_region(${endpointPrefix.dq()}, region.as_ref().expect("region must be specified")) + #T::DefaultAwsEndpointResolver::for_service(${endpointPrefix.dq()}) ) ),""", - StaticEndpoint(protocolConfig.runtimeConfig) + awsEndpoint(protocolConfig.runtimeConfig) ) } } } -fun EndpointProvider(runtimeConfig: RuntimeConfig) = RuntimeType("ProvideEndpoint", CargoDependency.OperationWip(runtimeConfig), "operationwip::endpoint") -fun StaticEndpoint(runtimeConfig: RuntimeConfig) = RuntimeType("StaticEndpoint", CargoDependency.OperationWip(runtimeConfig), "operationwip::endpoint") +fun AwsEndpoint(runtimeConfig: RuntimeConfig) = CargoDependency("aws-endpoint", Local(runtimeConfig.relativePath)) +fun EndpointProvider(runtimeConfig: RuntimeConfig) = + RuntimeType("ResolveAwsEndpoint", AwsEndpoint(runtimeConfig), "aws_endpoint") -class EndpointConfigPlugin(private val operationShape: OperationShape) : OperationCustomization() { +fun awsEndpoint(runtimeConfig: RuntimeConfig) = RuntimeType(null, AwsEndpoint(runtimeConfig), "aws_endpoint") +fun StaticEndpoint(runtimeConfig: RuntimeConfig) = + RuntimeType("Endpoint", CargoDependency.SmithyHttp(runtimeConfig), "smithy_http::endpoint") + +class EndpointConfigPlugin(private val runtimeConfig: RuntimeConfig, private val operationShape: OperationShape) : OperationCustomization() { override fun section(section: OperationSection): Writable { if (operationShape.hasTrait(EndpointTrait::class.java)) { TODO() } return when (section) { OperationSection.ImplBlock -> emptySection - OperationSection.Plugin -> writable { + is OperationSection.Feature -> writable { rust( """ - use operationwip::endpoint::EndpointProviderExt; - request.config_mut().insert_endpoint_provider(_config.endpoint_provider.clone()); - """ + + #T::set_endpoint_resolver(${section.config}.endpoint_provider.clone(), &mut ${section.request}.config_mut()); + """, + awsEndpoint(runtimeConfig) ) } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt index 94b431ef6b..655a569d32 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt @@ -7,6 +7,7 @@ package software.amazon.smithy.rustsdk import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.Local import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.writable @@ -28,7 +29,7 @@ class RegionConfig(runtimeConfig: RuntimeConfig) : ConfigCustomization() { ServiceConfig.BuilderImpl -> rust( """ - pub fn region(mut self, region: impl #T::ProvideRegion) -> Self { + pub fn region(mut self, region: impl #T::region::ProvideRegion) -> Self { self.region = region.region(); self } @@ -37,8 +38,8 @@ class RegionConfig(runtimeConfig: RuntimeConfig) : ConfigCustomization() { ) ServiceConfig.BuilderPreamble -> rust( """ - use #1T::ProvideRegion; - let region = self.region.or_else(||#1T::default_provider().region()); + use #1T::region::ProvideRegion; + let region = self.region.or_else(||#1T::region::default_provider().region()); """, region ) @@ -53,11 +54,11 @@ class RegionConfigPlugin(private val operationShape: OperationShape) : Operation override fun section(section: OperationSection): Writable { return when (section) { OperationSection.ImplBlock -> emptySection - OperationSection.Plugin -> writable { + is OperationSection.Feature -> writable { rust( """ - if let Some(region) = &_config.region { - request.config_mut().insert(region.clone()); + if let Some(region) = &${section.config}.region { + ${section.request}.config_mut().insert(region.clone()); } """ @@ -68,4 +69,6 @@ class RegionConfigPlugin(private val operationShape: OperationShape) : Operation } fun Region(runtimeConfig: RuntimeConfig) = - RuntimeType("region", CargoDependency.OperationWip(runtimeConfig), "operationwip") + RuntimeType(null, awsTypes(runtimeConfig), "aws_types") + +fun awsTypes(runtimeConfig: RuntimeConfig) = CargoDependency("aws-types", Local(runtimeConfig.relativePath)) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt index 3510864f38..64f6eb00a7 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.rustlang.Local import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.generators.OperationCustomization import software.amazon.smithy.rust.codegen.smithy.generators.OperationSection @@ -37,10 +38,11 @@ class SigV4SigningConfig(private val sigV4Trait: SigV4Trait) : ConfigCustomizati } } -class SigV4SigningPlugin(operationShape: OperationShape) : OperationCustomization() { +class SigV4SigningPlugin(operationShape: OperationShape, private val runtimeConfig: RuntimeConfig) : OperationCustomization() { override fun section(section: OperationSection): Writable { return when (section) { - is OperationSection.Plugin -> writable { + is OperationSection.Feature -> writable { + addDependency(CargoDependency.OperationWip(runtimeConfig)) rust( """ use operationwip::signing_middleware::SigningConfigExt; diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index 77baa85dbb..4c22178157 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -50,12 +50,25 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "aws-auth" version = "0.1.0" +dependencies = [ + "smithy-http", +] + +[[package]] +name = "aws-endpoint" +version = "0.1.0" +dependencies = [ + "aws-types", + "http", + "smithy-http", +] [[package]] name = "aws-hyper" version = "0.1.0" dependencies = [ "aws-auth", + "aws-endpoint", "aws-sig-auth", "bytes", "http", @@ -94,6 +107,10 @@ dependencies = [ "serde_urlencoded", ] +[[package]] +name = "aws-types" +version = "0.1.0" + [[package]] name = "bitflags" version = "1.2.1" @@ -163,6 +180,7 @@ dependencies = [ "http", "kms", "operationwip", + "smithy-http", "tokio", ] @@ -171,11 +189,13 @@ name = "dynamodb" version = "0.0.1" dependencies = [ "aws-auth", + "aws-endpoint", "aws-sig-auth", + "aws-types", "bytes", + "fastrand", "http", "operationwip", - "rand 0.7.3", "serde", "serde_json", "smithy-http", @@ -195,6 +215,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fastrand" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +dependencies = [ + "instant", +] + [[package]] name = "fnv" version = "1.0.7" @@ -265,17 +294,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.2" @@ -284,7 +302,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", - "wasi 0.10.1+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -443,7 +461,9 @@ name = "kms" version = "0.0.1" dependencies = [ "aws-auth", + "aws-endpoint", "aws-sig-auth", + "aws-types", "bytes", "http", "operationwip", @@ -629,6 +649,7 @@ version = "0.1.0" dependencies = [ "aws-auth", "aws-sig-auth", + "aws-types", "bytes", "http", "http-body", @@ -750,19 +771,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.3" @@ -770,19 +778,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.1", - "rand_hc 0.3.0", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] @@ -792,16 +790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.1", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -810,16 +799,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -828,7 +808,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.1", + "rand_core", ] [[package]] @@ -1050,7 +1030,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", "libc", - "rand 0.8.3", + "rand", "redox_syscall 0.2.4", "remove_dir_all", "winapi", @@ -1247,12 +1227,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.1+wasi-snapshot-preview1" diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.toml b/aws/sdk/examples/dynamo-helloworld/Cargo.toml index 4064dcd7ea..50a3143a11 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.toml +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.toml @@ -13,5 +13,6 @@ aws-hyper = { path = "../../build/aws-sdk/aws-hyper" } operationwip = { path = "../../build/aws-sdk/operationwip" } aws-auth = { path = "../../build/aws-sdk/aws-auth" } tokio = { version = "1", features = ["full"] } +smithy-http = { path = "../../build/aws-sdk/smithy-http"} http = "0.2.3" env_logger = "0.8.2" diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 8acbe90cbc..0aeeb8701e 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -16,8 +16,7 @@ use dynamodb::{ }; use env_logger::Env; use operationwip::endpoint::StaticEndpoint; -use operationwip::retry_policy::{RetryPolicy, RetryType}; -use tokio::time::Duration; +use smithy_http::endpoint::Endpoint; #[tokio::main] async fn main() -> Result<(), Box> { @@ -25,20 +24,19 @@ async fn main() -> Result<(), Box> { let config = dynamodb::Config::builder() .region("us-east-1") // To load credentials from environment variables, delete this line - .credentials_provider(auth::Credentials::from_keys( + .credentials_provider(aws_auth::Credentials::from_keys( "", "", None )) // To use real DynamoDB, delete this line: - .endpoint_provider(StaticEndpoint::from_uri(http::Uri::from_static( + .endpoint_provider(Endpoint::immutable(http::Uri::from_static( "http://localhost:8000", ))) .build(); let client = aws_hyper::Client::default().with_tracing(); let list_tables = dynamodb::operation::ListTables::builder() - .build(&config) - .with_policy(RetryIfNoTables); + .build(&config); let response = client.call(list_tables).await; let tables = match response { diff --git a/aws/sdk/examples/kms-helloworld/Cargo.lock b/aws/sdk/examples/kms-helloworld/Cargo.lock index 6c774197ae..5ac3b29193 100644 --- a/aws/sdk/examples/kms-helloworld/Cargo.lock +++ b/aws/sdk/examples/kms-helloworld/Cargo.lock @@ -29,12 +29,25 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "aws-auth" version = "0.1.0" +dependencies = [ + "smithy-http", +] + +[[package]] +name = "aws-endpoint" +version = "0.1.0" +dependencies = [ + "aws-types", + "http", + "smithy-http", +] [[package]] name = "aws-hyper" version = "0.1.0" dependencies = [ "aws-auth", + "aws-endpoint", "aws-sig-auth", "bytes", "http", @@ -73,6 +86,10 @@ dependencies = [ "serde_urlencoded", ] +[[package]] +name = "aws-types" +version = "0.1.0" + [[package]] name = "bitflags" version = "1.2.1" @@ -381,7 +398,9 @@ name = "kms" version = "0.0.1" dependencies = [ "aws-auth", + "aws-endpoint", "aws-sig-auth", + "aws-types", "bytes", "http", "operationwip", @@ -577,6 +596,7 @@ version = "0.1.0" dependencies = [ "aws-auth", "aws-sig-auth", + "aws-types", "bytes", "http", "http-body", From 712afbfacb6fff9f7db728b0fd206f8ae2221006 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 12 Feb 2021 18:46:46 -0500 Subject: [PATCH 48/50] Get everything working with new endpoints --- aws/rust-runtime/aws-hyper/Cargo.toml | 8 +- aws/rust-runtime/aws-hyper/src/lib.rs | 83 +----- aws/rust-runtime/operationwip/src/lib.rs | 1 - .../operationwip/src/middleware.rs | 275 ------------------ aws/sdk/build.gradle.kts | 2 +- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 13 + .../examples/dynamo-helloworld/src/main.rs | 1 - aws/sdk/examples/kms-helloworld/Cargo.lock | 13 + rust-runtime/smithy-http/src/operation.rs | 6 - 9 files changed, 43 insertions(+), 359 deletions(-) delete mode 100644 aws/rust-runtime/operationwip/src/middleware.rs diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index abe69264e7..1da4efe427 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -12,16 +12,18 @@ tower = { version = "0.4.2", features = ["retry", "buffer"] } operationwip = { path = "../operationwip" } middleware-tracing = { path = "../middleware-tracing" } hyper-tls = "0.5.0" -aws-auth = { path = "../aws-auth" } +aws-auth = { path = "../aws-auth" } aws-sig-auth = { path = "../aws-sig-auth" } aws-endpoint = { path = "../aws-endpoint" } http = "0.2.3" bytes = "1" http-body = "0.4.0" -tokio = { version = "1", features = ["time"]} +tokio = { version = "1", features = ["time"] } smithy-http = { path = "../../../rust-runtime/smithy-http" } +smithy-http-tower = { path = "../../../rust-runtime/smithy-http-tower" } pin-utils = "0.1.0" [dev-dependencies] -tokio = { version = "1", features = ["full"]} +tokio = { version = "1", features = ["full"] } tower-test = "0.4.0" +aws-types = { path = "../aws-types" } diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index 264ad24ac5..d018985b19 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,6 +1,5 @@ use bytes::Bytes; use hyper::Client as HyperClient; -use operationwip::middleware::OperationError; use smithy_http::body::SdkBody; use smithy_http::operation; use smithy_http::response::ParseHttpResponse; @@ -38,24 +37,6 @@ impl Client { } } -fn operation_error(o: OperationError) -> smithy_http::result::SdkError -where - OE: Into, -{ - match o { - OperationError::DispatchError(e) => { - smithy_http::result::SdkError::DispatchFailure(e.into()) - } - OperationError::ConstructionError(e) => { - smithy_http::result::SdkError::ConstructionFailure(e) - } - } -} - -#[derive(Clone)] -pub struct ParseResponseService { - inner: S, -} // In the future, this needs to use the CRT #[derive(Clone)] @@ -87,51 +68,6 @@ where } } -pub struct ParseResponseLayer; - -impl Layer for ParseResponseLayer -where - S: Service, -{ - type Service = ParseResponseService; - - fn layer(&self, inner: S) -> Self::Service { - ParseResponseService { inner } - } -} - -type BoxedResultFuture = Pin>>>; - -impl tower::Service> for ParseResponseService -where - S: Service, Error = OperationError>, - OE: Into, - S::Future: 'static, - B: http_body::Body + Unpin + From + 'static, - B::Error: Into, - O: ParseHttpResponse> + 'static, -{ - type Response = smithy_http::result::SdkSuccess; - type Error = smithy_http::result::SdkError; - type Future = BoxedResultFuture; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx).map_err(operation_error) - } - - fn call(&mut self, req: Operation) -> Self::Future { - let (req, handler) = req.into_request_response(); - let resp = self.inner.call(req); - let fut = async move { - match resp.await { - Err(e) => Err(operation_error::(e)), - Ok(resp) => load_response(resp, &handler).await, - } - }; - Box::pin(fut) - } -} - impl Client where S: Service, Response = http::Response> @@ -161,16 +97,16 @@ where O: ParseHttpResponse> + Send + Clone + 'static, Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { - let signer = OperationPipelineService::for_stage(SignRequestStage::new()); - let endpoint_resolver = OperationPipelineService::for_stage(AwsEndpointStage); + let signer = MapRequestLayer::for_mapper(SignRequestStage::new()); + let endpoint_resolver = MapRequestLayer::for_mapper(AwsEndpointStage); let inner = self.inner.clone(); let mut svc = ServiceBuilder::new() .retry(RetryStrategy {}) .map_request(|r: Operation| r) - .layer(ParseResponseLayer) + .layer(ParseResponseLayer::::new()) .layer(endpoint_resolver) .layer(signer) - .layer(DispatchLayer) + .layer(DispatchLayer::new()) .service(inner); svc.ready_and().await?.call(input).await @@ -182,7 +118,6 @@ where use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; -use operationwip::middleware::{DispatchLayer, OperationPipelineService}; use operationwip::retry_policy::RetryPolicy; use operationwip::signing_middleware::SignRequestStage; use smithy_http::middleware::load_response; @@ -192,6 +127,9 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; use aws_endpoint::AwsEndpointStage; +use smithy_http_tower::map_request::MapRequestLayer; +use smithy_http_tower::parse_response::ParseResponseLayer; +use smithy_http_tower::dispatch::DispatchLayer; #[cfg(test)] mod test { @@ -201,7 +139,6 @@ mod test { use bytes::Bytes; use http::header::AUTHORIZATION; use http::{Request, Response, Uri}; - use operationwip::region::Region; use operationwip::signing_middleware::SigningConfigExt; use pin_utils::core_reexport::task::{Context, Poll}; use smithy_http::body::SdkBody; @@ -215,6 +152,7 @@ mod test { use std::sync::{mpsc, Arc}; use std::time::Duration; use std::time::UNIX_EPOCH; + use aws_types::Region; #[derive(Clone)] struct TestService { @@ -265,6 +203,7 @@ mod test { } } + /* #[tokio::test] async fn e2e_service() { #[derive(Debug)] @@ -291,7 +230,7 @@ mod test { config.insert_credentials_provider(Arc::new(Credentials::from_keys( "access", "secret", None, ))); - config.insert_endpoint_provider(Arc::new(StaticEndpoint::from_uri(Uri::from_static( + config.insert_endpoint_provider(Arc::new(Endpoint::from_uri(Uri::from_static( "http://localhost:8000", )))); Result::<_, ()>::Ok(req) @@ -315,5 +254,5 @@ mod test { vec!["host", "authorization", "x-amz-date"] ); assert_eq!(request.headers().get(AUTHORIZATION).unwrap(), "AWS4-HMAC-SHA256 Credential=access/20210120/some-region/some-service/aws4_request, SignedHeaders=host, Signature=f179c6899f0a11051a11dc1bb022252b0741953663bc5ff33dfa2abfed51e0b1"); - } + }*/ } diff --git a/aws/rust-runtime/operationwip/src/lib.rs b/aws/rust-runtime/operationwip/src/lib.rs index 7619ff71fb..72fcb9b18d 100644 --- a/aws/rust-runtime/operationwip/src/lib.rs +++ b/aws/rust-runtime/operationwip/src/lib.rs @@ -1,3 +1,2 @@ -pub mod middleware; pub mod retry_policy; pub mod signing_middleware; diff --git a/aws/rust-runtime/operationwip/src/middleware.rs b/aws/rust-runtime/operationwip/src/middleware.rs deleted file mode 100644 index 163ae77d49..0000000000 --- a/aws/rust-runtime/operationwip/src/middleware.rs +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -use std::error::Error; -use std::future::Future; -use std::pin::Pin; -use std::task::{Context, Poll}; -use tower::{Layer, Service}; -type BoxError = Box; -use pin_project::pin_project; -use smithy_http::body::SdkBody; -use smithy_http::operation; -use smithy_http::middleware::MapRequest; - -#[derive(Clone)] -pub struct OperationRequestMiddlewareService { - inner: S, - middleware: M, -} - -pub struct OperationPipelineService { - layer: M, -} - -impl OperationPipelineService { - pub fn for_stage(layer: M) -> Self { - OperationPipelineService { layer } - } -} - -impl Layer for OperationPipelineService -where - M: Clone, -{ - type Service = OperationRequestMiddlewareService; - - fn layer(&self, inner: S) -> Self::Service { - OperationRequestMiddlewareService { - inner, - middleware: self.layer.clone(), - } - } -} - -pub trait RequestConstructionErr { - fn request_error(err: BoxError) -> Self; -} - -#[pin_project(project = EnumProj)] -pub enum OperationMiddlewareFuture { - Inner(#[pin] F), - Ready(Option), -} - -impl Future for OperationMiddlewareFuture -where - F: Future>, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.project() { - EnumProj::Ready(e) => Poll::Ready(Err(e.take().unwrap())), - EnumProj::Inner(f) => f.poll(cx), - } - } -} - -impl Service for OperationRequestMiddlewareService -where - S: Service, - M: MapRequest, - S::Error: RequestConstructionErr, -{ - type Response = S::Response; - type Error = S::Error; - type Future = OperationMiddlewareFuture; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: operation::Request) -> Self::Future { - match self - .middleware - .apply(req) - .map_err(|e| S::Error::request_error(e.into())) - { - Err(e) => OperationMiddlewareFuture::Ready(Some(e)), - Ok(req) => OperationMiddlewareFuture::Inner(self.inner.call(req)), - } - } -} - -/// Connects Operation driven middleware to an HTTP implementation. -/// -/// It will also wrap the error type in OperationError to enable operation middleware -/// reporting specific errors -#[derive(Clone)] -pub struct DispatchMiddleware { - inner: S, -} - -pub fn to_request( - request: operation::Request, -) -> Result, OperationError> { - Ok(request.into_parts().0) -} - -#[derive(Clone, Copy)] -pub struct DispatchLayer; - -impl Layer for DispatchLayer -where - S: Service>, -{ - type Service = DispatchMiddleware; - - fn layer(&self, inner: S) -> Self::Service { - DispatchMiddleware { inner } - } -} - -#[derive(Debug)] -pub enum OperationError { - DispatchError(E), - ConstructionError(Box), -} - -impl RequestConstructionErr for OperationError { - fn request_error(err: Box) -> Self { - OperationError::ConstructionError(err) - } -} - -#[pin_project] -pub struct OperationFuture { - #[pin] - f: F, -} - -impl Future for OperationFuture -where - F: Future>, -{ - type Output = Result>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.project(); - this.f.poll(cx).map_err(OperationError::DispatchError) - } -} - -impl Service for DispatchMiddleware -where - S: Service>, -{ - type Response = S::Response; - type Error = OperationError; - type Future = OperationFuture; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner - .poll_ready(cx) - .map_err(OperationError::DispatchError) - } - - fn call(&mut self, req: operation::Request) -> Self::Future { - let (req, _propery_bag) = req.into_parts(); - OperationFuture { - f: self.inner.call(req), - } - } -} - -#[cfg(test)] -mod test { - use crate::middleware::{DispatchLayer, OperationPipelineService}; - use bytes::Bytes; - use http::header::HeaderName; - use http::{HeaderValue, Request, Response}; - use std::str::FromStr; - - use smithy_http::body::SdkBody; - use smithy_http::operation; - use smithy_http::response::ParseHttpResponse; - use std::convert::Infallible; - use tower::service_fn; - use tower::{Layer, Service}; - use smithy_http::middleware::MapRequest; - - struct TestOperationParser; - - impl ParseHttpResponse for TestOperationParser - where - B: http_body::Body, - { - type Output = String; - - fn parse_unloaded(&self, _response: &mut Response) -> Option { - Some("Hello!".to_string()) - } - - fn parse_loaded(&self, _response: &Response) -> Self::Output { - "Hello!".to_string() - } - } - - #[tokio::test] - async fn middleware_test() { - #[derive(Clone)] - struct AddHeader(String, String); - impl MapRequest for AddHeader { - type Error = Infallible; - fn apply( - &self, - request: operation::Request, - ) -> Result { - request.augment(|mut request, _| { - request.headers_mut().append( - HeaderName::from_str(&self.0).unwrap(), - HeaderValue::from_str(&self.0).unwrap(), - ); - Ok(request) - }) - } - } - - let add_header = OperationPipelineService::for_stage(AddHeader( - "X-Key".to_string(), - "X-Value".to_string(), - )); - let http_service = service_fn(|request: Request| async move { - if request.uri().to_string().as_str() == "123" { - Err("invalid url") - } else { - Ok(http::Response::new( - request - .headers() - .iter() - .map(|(k, v)| format!("{}:{:?}", k, v)) - .collect::(), - )) - } - }); - let mut service = add_header.layer(DispatchLayer.layer(http_service)); - let operation = operation::Request::new( - Request::builder() - .uri("/some_url") - .body(SdkBody::from("Hello")) - .unwrap(), - ); /*, - signing_config: SigningConfig::Http(HttpSigningConfig { - algorithm: SigningAlgorithm::SigV4, - signature_type: HttpSignatureType::HttpRequestHeaders, - service_config: ServiceConfig { - service: "svc".to_string(), - region: "region".to_string(), - }, - request_config: RequestConfig { - request_ts: || SystemTime::now(), - }, - double_uri_encode: false, - normalize_uri_path: false, - omit_session_token: false, - }), - credentials_provider: Box::new(Credentials::from_static("key", "secret", None)), - endpoint_config: Box::new(StaticEndpoint::from_service_region("dynamodb", "us-east-1")), - };*/ - let response = service.call(operation).await; - assert_eq!(response.unwrap().body(), "x-key:\"X-Key\""); - } -} diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index f25b3062e9..91d23baff6 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -21,7 +21,7 @@ val smithyVersion: String by project val sdkOutputDir = buildDir.resolve("aws-sdk") val awsServices = discoverServices() // TODO: smithy-http should be removed -val runtimeModules = listOf("smithy-types", "smithy-http") +val runtimeModules = listOf("smithy-types", "smithy-http", "smithy-http-tower") val examples = listOf("dynamo-helloworld", "kms-helloworld") val awsModules = listOf("aws-auth", "aws-endpoint", "aws-types", "operationwip", "aws-hyper", "middleware-tracing", "aws-sig-auth") diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index 4c22178157..63c31275c3 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -79,6 +79,7 @@ dependencies = [ "operationwip", "pin-utils", "smithy-http", + "smithy-http-tower", "tokio", "tower", ] @@ -987,6 +988,18 @@ dependencies = [ "smithy-types", ] +[[package]] +name = "smithy-http-tower" +version = "0.1.0" +dependencies = [ + "bytes", + "http", + "http-body", + "pin-project 1.0.4", + "smithy-http", + "tower", +] + [[package]] name = "smithy-types" version = "0.0.1" diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index 0aeeb8701e..c8af5e4373 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -15,7 +15,6 @@ use dynamodb::{ operation::CreateTable, }; use env_logger::Env; -use operationwip::endpoint::StaticEndpoint; use smithy_http::endpoint::Endpoint; #[tokio::main] diff --git a/aws/sdk/examples/kms-helloworld/Cargo.lock b/aws/sdk/examples/kms-helloworld/Cargo.lock index 5ac3b29193..841c5f8129 100644 --- a/aws/sdk/examples/kms-helloworld/Cargo.lock +++ b/aws/sdk/examples/kms-helloworld/Cargo.lock @@ -58,6 +58,7 @@ dependencies = [ "operationwip", "pin-utils", "smithy-http", + "smithy-http-tower", "tokio", "tower", ] @@ -934,6 +935,18 @@ dependencies = [ "smithy-types", ] +[[package]] +name = "smithy-http-tower" +version = "0.1.0" +dependencies = [ + "bytes", + "http", + "http-body", + "pin-project 1.0.5", + "smithy-http", + "tower", +] + [[package]] name = "smithy-types" version = "0.0.1" diff --git a/rust-runtime/smithy-http/src/operation.rs b/rust-runtime/smithy-http/src/operation.rs index 56f3fb920f..86191b561c 100644 --- a/rust-runtime/smithy-http/src/operation.rs +++ b/rust-runtime/smithy-http/src/operation.rs @@ -9,12 +9,6 @@ pub struct Operation { _retry_policy: R, } -impl Operation { - pub fn into_request_response(self) -> (Request, H) { - (self.request, self.response_handler) - } -} - impl Operation { pub fn new(request: Request, response_handler: H) -> Self { Operation { From 8737b8e426e8aa496456bf1787bac35355082441 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 12 Feb 2021 18:51:03 -0500 Subject: [PATCH 49/50] Cleanup unused imports --- aws/rust-runtime/aws-hyper/src/lib.rs | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index d018985b19..b36d3f40f4 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,10 +1,10 @@ -use bytes::Bytes; + use hyper::Client as HyperClient; use smithy_http::body::SdkBody; use smithy_http::operation; use smithy_http::response::ParseHttpResponse; use std::error::Error; -use tower::{Layer, Service, ServiceBuilder, ServiceExt}; +use tower::{Service, ServiceBuilder, ServiceExt}; type BoxError = Box; @@ -120,11 +120,11 @@ use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; use operationwip::retry_policy::RetryPolicy; use operationwip::signing_middleware::SignRequestStage; -use smithy_http::middleware::load_response; + use smithy_http::operation::Operation; use std::future::Future; use std::pin::Pin; -use std::task::{Context, Poll}; + use std::time::Duration; use aws_endpoint::AwsEndpointStage; use smithy_http_tower::map_request::MapRequestLayer; @@ -133,26 +133,26 @@ use smithy_http_tower::dispatch::DispatchLayer; #[cfg(test)] mod test { - use crate::{BoxError, Client}; - use aws_auth::Credentials; - use aws_sig_auth::OperationSigningConfig; + use crate::{BoxError}; + + use bytes::Bytes; - use http::header::AUTHORIZATION; - use http::{Request, Response, Uri}; - use operationwip::signing_middleware::SigningConfigExt; + + use http::{Request, Response}; + use pin_utils::core_reexport::task::{Context, Poll}; use smithy_http::body::SdkBody; - use smithy_http::operation; - use smithy_http::operation::Operation; + + use smithy_http::response::ParseHttpResponse; - use std::error::Error; - use std::fmt::Formatter; + + use std::future::Future; use std::pin::Pin; - use std::sync::{mpsc, Arc}; - use std::time::Duration; - use std::time::UNIX_EPOCH; - use aws_types::Region; + use std::sync::{mpsc}; + + + #[derive(Clone)] struct TestService { From c6c45a685874fda8ddb22ab02136d4e2a2afa286 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 12 Feb 2021 20:40:57 -0500 Subject: [PATCH 50/50] working again --- aws/rust-runtime/aws-hyper/src/lib.rs | 21 +-- aws/rust-runtime/operationwip/src/lib.rs | 1 - .../operationwip/src/signing_middleware.rs | 126 ------------------ .../amazon/smithy/rustsdk/RegionConfig.kt | 8 +- .../amazon/smithy/rustsdk/SigningConfig.kt | 17 +-- aws/sdk/examples/dynamo-helloworld/Cargo.lock | 23 ++++ .../examples/dynamo-helloworld/src/main.rs | 2 - aws/sdk/examples/kms-helloworld/Cargo.lock | 23 ++++ rust-runtime/smithy-http/src/operation.rs | 12 ++ 9 files changed, 78 insertions(+), 155 deletions(-) delete mode 100644 aws/rust-runtime/operationwip/src/signing_middleware.rs diff --git a/aws/rust-runtime/aws-hyper/src/lib.rs b/aws/rust-runtime/aws-hyper/src/lib.rs index b36d3f40f4..38914b1eb1 100644 --- a/aws/rust-runtime/aws-hyper/src/lib.rs +++ b/aws/rust-runtime/aws-hyper/src/lib.rs @@ -1,4 +1,3 @@ - use hyper::Client as HyperClient; use smithy_http::body::SdkBody; use smithy_http::operation; @@ -37,7 +36,6 @@ impl Client { } } - // In the future, this needs to use the CRT #[derive(Clone)] struct RetryStrategy {} @@ -97,7 +95,7 @@ where O: ParseHttpResponse> + Send + Clone + 'static, Retry: RetryPolicy, SdkError> + Send + Clone + 'static, { - let signer = MapRequestLayer::for_mapper(SignRequestStage::new()); + let signer = MapRequestLayer::for_mapper(SigV4SigningStage::new(SigV4Signer::new())); let endpoint_resolver = MapRequestLayer::for_mapper(AwsEndpointStage); let inner = self.inner.clone(); let mut svc = ServiceBuilder::new() @@ -119,22 +117,22 @@ use hyper::client::HttpConnector; use hyper_tls::HttpsConnector; use middleware_tracing::RawRequestLogging; use operationwip::retry_policy::RetryPolicy; -use operationwip::signing_middleware::SignRequestStage; use smithy_http::operation::Operation; use std::future::Future; use std::pin::Pin; -use std::time::Duration; use aws_endpoint::AwsEndpointStage; +use aws_sig_auth::middleware::SigV4SigningStage; +use aws_sig_auth::signer::SigV4Signer; +use smithy_http_tower::dispatch::DispatchLayer; use smithy_http_tower::map_request::MapRequestLayer; use smithy_http_tower::parse_response::ParseResponseLayer; -use smithy_http_tower::dispatch::DispatchLayer; +use std::time::Duration; #[cfg(test)] mod test { - use crate::{BoxError}; - + use crate::BoxError; use bytes::Bytes; @@ -143,16 +141,11 @@ mod test { use pin_utils::core_reexport::task::{Context, Poll}; use smithy_http::body::SdkBody; - use smithy_http::response::ParseHttpResponse; - use std::future::Future; use std::pin::Pin; - use std::sync::{mpsc}; - - - + use std::sync::mpsc; #[derive(Clone)] struct TestService { diff --git a/aws/rust-runtime/operationwip/src/lib.rs b/aws/rust-runtime/operationwip/src/lib.rs index 72fcb9b18d..27b2a1f3e0 100644 --- a/aws/rust-runtime/operationwip/src/lib.rs +++ b/aws/rust-runtime/operationwip/src/lib.rs @@ -1,2 +1 @@ pub mod retry_policy; -pub mod signing_middleware; diff --git a/aws/rust-runtime/operationwip/src/signing_middleware.rs b/aws/rust-runtime/operationwip/src/signing_middleware.rs deleted file mode 100644 index 50f21470d9..0000000000 --- a/aws/rust-runtime/operationwip/src/signing_middleware.rs +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ -use aws_auth::ProvideCredentials; -use aws_sig_auth::{ - HttpSigner, HttpSigningConfig, OperationSigningConfig, RequestConfig, SigningConfig, -}; -use http::Request; -use smithy_http::operation; -use smithy_http::property_bag::PropertyBag; -use std::sync::Arc; -use std::time::SystemTime; -use tower::BoxError; -use smithy_http::middleware::MapRequest; -use aws_types::SigningRegion; - -#[derive(Clone)] -pub struct SignRequestStage { - signer: HttpSigner, -} - -impl Default for SignRequestStage { - fn default() -> Self { - SignRequestStage::new() - } -} - -impl SignRequestStage { - pub fn new() -> Self { - SignRequestStage { - signer: HttpSigner {}, - } - } -} - -pub trait SigningConfigExt { - fn signing_config(&self) -> Option<&OperationSigningConfig>; - fn insert_signing_config( - &mut self, - signing_config: OperationSigningConfig, - ) -> Option; -} - -impl SigningConfigExt for PropertyBag { - fn signing_config(&self) -> Option<&OperationSigningConfig> { - self.get() - } - - fn insert_signing_config( - &mut self, - signing_config: OperationSigningConfig, - ) -> Option { - self.insert(signing_config) - } -} - -pub trait CredentialProviderExt { - fn credentials_provider(&self) -> Option<&Arc>; - fn insert_credentials_provider( - &mut self, - provider: Arc, - ) -> Option>; -} - -impl CredentialProviderExt for PropertyBag { - fn credentials_provider(&self) -> Option<&Arc> { - self.get() - } - - fn insert_credentials_provider( - &mut self, - provider: Arc, - ) -> Option> { - self.insert(provider) - } -} - -impl MapRequest for SignRequestStage { - type Error = BoxError; - fn apply(&self, request: operation::Request) -> Result { - request.augment(|request, config| { - let operation_config = config.signing_config().ok_or("Missing signing config")?; - let cred_provider = config - .credentials_provider() - .ok_or("Missing credentials provider")?; - let creds = match cred_provider.credentials() { - Ok(creds) => creds, - Err(e) => return Err(e.into()), - }; - let region = config.get::() - .ok_or("Can't sign; No region defined")? - .as_ref().to_string(); - let request_config = RequestConfig { - request_ts: config - .get::() - .copied() - .unwrap_or_else(SystemTime::now), - region: region.into(), - }; - let signing_config = SigningConfig::Http(HttpSigningConfig { - operation_config: operation_config.clone(), - request_config, - }); - - let (parts, body) = request.into_parts(); - let signable_body = match body.bytes() { - Some(bytes) => bytes, - None => { - return Err("Cannot convert body to signing payload (body is streaming)".into()) - } // in the future, chan variants which will cause an error - }; - let mut signable_request = http::Request::from_parts(parts, signable_body); - - match signing_config { - SigningConfig::Http(config) => { - if let Err(e) = self.signer.sign(&config, &creds, &mut signable_request) { - return Err(e as _); - } - } - }; - let (signed_parts, _) = signable_request.into_parts(); - Ok(Request::from_parts(signed_parts, body)) - }) - } -} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt index 655a569d32..2cdf3edd41 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionConfig.kt @@ -19,7 +19,7 @@ import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustom import software.amazon.smithy.rust.codegen.smithy.generators.config.ServiceConfig class RegionConfig(runtimeConfig: RuntimeConfig) : ConfigCustomization() { - private val region = Region(runtimeConfig) + private val region = awsTypes(runtimeConfig) override fun section(section: ServiceConfig) = writable { when (section) { is ServiceConfig.ConfigStruct -> rust("pub region: Option<#T::Region>,", region) @@ -68,7 +68,7 @@ class RegionConfigPlugin(private val operationShape: OperationShape) : Operation } } -fun Region(runtimeConfig: RuntimeConfig) = - RuntimeType(null, awsTypes(runtimeConfig), "aws_types") +fun awsTypes(runtimeConfig: RuntimeConfig) = + RuntimeType(null, awsTypesDep(runtimeConfig), "aws_types") -fun awsTypes(runtimeConfig: RuntimeConfig) = CargoDependency("aws-types", Local(runtimeConfig.relativePath)) +fun awsTypesDep(runtimeConfig: RuntimeConfig) = CargoDependency("aws-types", Local(runtimeConfig.relativePath)) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt index 64f6eb00a7..193cada628 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigningConfig.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.Local import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.smithy.RuntimeType @@ -38,21 +39,21 @@ class SigV4SigningConfig(private val sigV4Trait: SigV4Trait) : ConfigCustomizati } } -class SigV4SigningPlugin(operationShape: OperationShape, private val runtimeConfig: RuntimeConfig) : OperationCustomization() { +class SigV4SigningPlugin(operationShape: OperationShape, private val runtimeConfig: RuntimeConfig) : + OperationCustomization() { override fun section(section: OperationSection): Writable { return when (section) { is OperationSection.Feature -> writable { addDependency(CargoDependency.OperationWip(runtimeConfig)) - rust( + rustTemplate( """ - use operationwip::signing_middleware::SigningConfigExt; - request.config_mut().insert_signing_config( - #T::OperationSigningConfig::default_config(_config.signing_service()) + request.config_mut().insert( + #{sig_auth}::signer::OperationSigningConfig::default_config() ); - use operationwip::signing_middleware::CredentialProviderExt; - request.config_mut().insert_credentials_provider(_config.credentials_provider.clone()); + request.config_mut().insert(#{aws_types}::SigningService::from_static(${section.config}.signing_service())); """, - awsSigAuth + "sig_auth" to awsSigAuth, + "aws_types" to awsTypes(runtimeConfig) ) } else -> emptySection diff --git a/aws/sdk/examples/dynamo-helloworld/Cargo.lock b/aws/sdk/examples/dynamo-helloworld/Cargo.lock index 63c31275c3..c862db5b87 100644 --- a/aws/sdk/examples/dynamo-helloworld/Cargo.lock +++ b/aws/sdk/examples/dynamo-helloworld/Cargo.lock @@ -90,7 +90,10 @@ version = "0.1.0" dependencies = [ "aws-auth", "aws-sigv4", + "aws-types", "http", + "smithy-http", + "thiserror", ] [[package]] @@ -1058,6 +1061,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.2" diff --git a/aws/sdk/examples/dynamo-helloworld/src/main.rs b/aws/sdk/examples/dynamo-helloworld/src/main.rs index c8af5e4373..535712215f 100644 --- a/aws/sdk/examples/dynamo-helloworld/src/main.rs +++ b/aws/sdk/examples/dynamo-helloworld/src/main.rs @@ -6,8 +6,6 @@ use std::error::Error; use aws_hyper::{SdkError, SdkSuccess}; -use dynamodb::error::ListTablesError; -use dynamodb::output::ListTablesOutput; use dynamodb::{ model::{ AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType, diff --git a/aws/sdk/examples/kms-helloworld/Cargo.lock b/aws/sdk/examples/kms-helloworld/Cargo.lock index 841c5f8129..7b9f6b9dd4 100644 --- a/aws/sdk/examples/kms-helloworld/Cargo.lock +++ b/aws/sdk/examples/kms-helloworld/Cargo.lock @@ -69,7 +69,10 @@ version = "0.1.0" dependencies = [ "aws-auth", "aws-sigv4", + "aws-types", "http", + "smithy-http", + "thiserror", ] [[package]] @@ -1005,6 +1008,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.3" diff --git a/rust-runtime/smithy-http/src/operation.rs b/rust-runtime/smithy-http/src/operation.rs index 64a37d2eb2..ec4f07b1da 100644 --- a/rust-runtime/smithy-http/src/operation.rs +++ b/rust-runtime/smithy-http/src/operation.rs @@ -13,6 +13,18 @@ impl Operation { pub fn into_request_response(self) -> (Request, H) { (self.request, self.response_handler) } + + pub fn retry_policy(&self) -> &R { + &self._retry_policy + } + + pub fn try_clone(&self) -> Option where H: Clone, R: Clone { + Some(Operation { + request: self.request.try_clone()?, + response_handler: self.response_handler.clone(), + _retry_policy: self._retry_policy.clone() + }) + } } impl Operation {