Unverified Commit 6dceb8c0 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Move default endpoint resolver into a runtime plugin (#3072)

## Motivation and Context
In preparation for inlining the old endpoint traits, I'm cleaning up the
endpoint resolver behavior.

## Description

1. The `Config` field of `service_runtime_plugin` was unused to I
deleted it
2. Store the endpoint resolver in `RuntimeComponents` instead of in
operation config. This allows a lot of complex logic around
`ConfigOverride` to be removed.
3. Move the default endpoint resolver into a runtime plugin.
4. Don't have a fallback implementation for `EndpointResolver`, allow
final construction of `RuntimeComponents` to fail
5. `ServiceRuntimePlugin` has been changed to `Defaults` so that it
doesn't overwrite settings set by the service config


## Testing
Well covered by existing UT / IT
## Checklist
<!--- If a checkbox below is not applicable, then please DELETE it
rather than leaving it unchecked -->
- [x] I have updated `CHANGELOG.next.toml` if I made changes to the
smithy-rs codegen or runtime crates
- [x] I have updated `CHANGELOG.next.toml` if I made changes to the AWS
SDK, generated SDK code, or SDK runtime crates

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
parent 0f38daea
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -408,3 +408,9 @@ message = "`RuntimeComponents` have been added as an argument to the `IdentityRe
references = ["smithy-rs#2917"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client"}
author = "jdisanti"

[[smithy-rs]]
message = "The `idempotency_provider` field has been removed from config as a public field. If you need access to this field, it is still available from the context of an interceptor."
references = ["smithy-rs#3072"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client" }
author = "rcoh"
+2 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.rust.codegen.client.smithy.customizations.ClientCustomizations
import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpAuthDecorator
import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpConnectorConfigDecorator
import software.amazon.smithy.rust.codegen.client.smithy.customizations.IdempotencyTokenDecorator
import software.amazon.smithy.rust.codegen.client.smithy.customizations.NoAuthDecorator
import software.amazon.smithy.rust.codegen.client.smithy.customizations.SensitiveOutputDecorator
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
@@ -66,6 +67,7 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() {
                HttpAuthDecorator(),
                HttpConnectorConfigDecorator(),
                SensitiveOutputDecorator(),
                IdempotencyTokenDecorator(),
                *decorator,
            )

+60 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package software.amazon.smithy.rust.codegen.client.smithy.customizations

import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.IdempotencyTokenProviderCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.needsIdempotencyToken
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.util.extendIf

class IdempotencyTokenDecorator : ClientCodegenDecorator {
    override val name: String = "IdempotencyToken"
    override val order: Byte = 0

    private fun enabled(ctx: ClientCodegenContext) = ctx.serviceShape.needsIdempotencyToken(ctx.model)
    override fun configCustomizations(
        codegenContext: ClientCodegenContext,
        baseCustomizations: List<ConfigCustomization>,
    ): List<ConfigCustomization> = baseCustomizations.extendIf(enabled(codegenContext)) {
        IdempotencyTokenProviderCustomization(codegenContext)
    }

    override fun operationCustomizations(
        codegenContext: ClientCodegenContext,
        operation: OperationShape,
        baseCustomizations: List<OperationCustomization>,
    ): List<OperationCustomization> {
        return baseCustomizations + IdempotencyTokenGenerator(codegenContext, operation)
    }

    override fun serviceRuntimePluginCustomizations(
        codegenContext: ClientCodegenContext,
        baseCustomizations: List<ServiceRuntimePluginCustomization>,
    ): List<ServiceRuntimePluginCustomization> {
        return baseCustomizations.extendIf(enabled(codegenContext)) {
            object : ServiceRuntimePluginCustomization() {
                override fun section(section: ServiceRuntimePluginSection) = writable {
                    if (section is ServiceRuntimePluginSection.AdditionalConfig) {
                        section.putConfigValue(this, defaultTokenProvider((codegenContext.runtimeConfig)))
                    }
                }
            }
        }
    }
}

private fun defaultTokenProvider(runtimeConfig: RuntimeConfig) =
    writable { rust("#T()", RuntimeType.idempotencyToken(runtimeConfig).resolve("default_provider")) }
+19 −30
Original line number Diff line number Diff line
@@ -20,12 +20,13 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
import software.amazon.smithy.rust.codegen.core.smithy.isOptional
import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE
import software.amazon.smithy.rust.codegen.core.util.findMemberWithTrait
import software.amazon.smithy.rust.codegen.core.util.inputShape

class IdempotencyTokenGenerator(
    codegenContext: CodegenContext,
    operationShape: OperationShape,
    private val operationShape: OperationShape,
) : OperationCustomization() {
    private val model = codegenContext.model
    private val runtimeConfig = codegenContext.runtimeConfig
@@ -47,13 +48,16 @@ class IdempotencyTokenGenerator(
                    "/inlineable/src/client_idempotency_token.rs",
                    CargoDependency.smithyRuntimeApi(runtimeConfig),
                    CargoDependency.smithyTypes(runtimeConfig),
                    InlineDependency.idempotencyToken(runtimeConfig),
                ).toType().resolve("IdempotencyTokenRuntimePlugin"),
        )

        return when (section) {
            is OperationSection.AdditionalRuntimePlugins -> writable {
                section.addOperationRuntimePlugin(this) {
                    if (symbolProvider.toSymbol(idempotencyTokenMember).isOptional()) {
                    if (!symbolProvider.toSymbol(idempotencyTokenMember).isOptional()) {
                        UNREACHABLE("top level input members are always optional. $operationShape")
                    }
                    // An idempotency token is optional. If the user didn't specify a token
                    // then we'll generate one and set it.
                    rustTemplate(
@@ -67,24 +71,9 @@ class IdempotencyTokenGenerator(
                        """,
                        *codegenScope,
                    )
                    } else {
                        // An idempotency token is required, but it'll be set to an empty string if
                        // the user didn't specify one. If that's the case, then we'll generate one
                        // and set it.
                        rustTemplate(
                            """
                            #{IdempotencyTokenRuntimePlugin}::new(|token_provider, input| {
                                let input: &mut #{Input} = input.downcast_mut().expect("correct type");
                                if input.$memberName.is_empty() {
                                    input.$memberName = token_provider.make_idempotency_token();
                                }
                            })
                            """,
                            *codegenScope,
                        )
                    }
                }
            }

            else -> emptySection
        }
    }
+0 −2
Original line number Diff line number Diff line
@@ -10,7 +10,6 @@ import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
import software.amazon.smithy.rust.codegen.client.smithy.customizations.ConnectionPoisoningRuntimePluginCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpChecksumRequiredGenerator
import software.amazon.smithy.rust.codegen.client.smithy.customizations.IdempotencyTokenGenerator
import software.amazon.smithy.rust.codegen.client.smithy.customizations.InterceptorConfigCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.MetadataCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyConfigCustomization
@@ -50,7 +49,6 @@ class RequiredCustomizations : ClientCodegenDecorator {
    ): List<OperationCustomization> =
        baseCustomizations +
            MetadataCustomization(codegenContext, operation) +
            IdempotencyTokenGenerator(codegenContext, operation) +
            HttpChecksumRequiredGenerator(codegenContext, operation) +
            RetryClassifierOperationCustomization(codegenContext, operation)

Loading