Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(codegen): http checksum dependency integration #3346

Merged
merged 6 commits into from Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,190 @@
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
trivikr marked this conversation as resolved.
Show resolved Hide resolved
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.smithy.aws.typescript.codegen;

import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Consumer;
import software.amazon.smithy.aws.traits.HttpChecksumTrait;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.TopDownIndex;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.typescript.codegen.LanguageTarget;
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
import software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin;
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
import software.amazon.smithy.utils.ListUtils;
import software.amazon.smithy.utils.MapUtils;
import software.amazon.smithy.utils.SmithyInternalApi;

/**
* Adds checksum dependencies if needed.
*/
@SmithyInternalApi
public class AddHttpChecksumDependency implements TypeScriptIntegration {

@Override
public void addConfigInterfaceFields(
TypeScriptSettings settings,
Model model,
SymbolProvider symbolProvider,
TypeScriptWriter writer
) {
if (!hasHttpChecksumTrait(model, settings.getService(model))) {
return;
}

writer.addImport("Readable", "Readable", "stream");
writer.addImport("StreamHasher", "__StreamHasher", "@aws-sdk/types");
writer.writeDocs("A function that, given a hash constructor and a stream, calculates the \n"
+ "hash of the streamed value.\n"
+ "@internal");
writer.write("streamHasher?: __StreamHasher<Readable> | __StreamHasher<Blob>;\n");

writer.addImport("Hash", "__Hash", "@aws-sdk/types");
writer.addImport("HashConstructor", "__HashConstructor", "@aws-sdk/types");

writer.writeDocs("A constructor for a class implementing the {@link __Hash} interface \n"
+ "that computes MD5 hashes.\n"
+ "@internal");
writer.write("md5?: __HashConstructor;\n");

writer.writeDocs("A constructor for a class implementing the {@link __Hash} interface \n"
+ "that computes SHA1 hashes.\n"
+ "@internal");
writer.write("sha1?: __HashConstructor;\n");
}

@Override
public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
TypeScriptSettings settings,
Model model,
SymbolProvider symbolProvider,
LanguageTarget target
) {
if (!hasHttpChecksumTrait(model, settings.getService(model))) {
return Collections.emptyMap();
}

switch (target) {
case NODE:
return MapUtils.of(
"streamHasher", writer -> {
writer.addDependency(TypeScriptDependency.STREAM_HASHER_NODE);
writer.addImport("readableStreamHasher", "streamHasher",
TypeScriptDependency.STREAM_HASHER_NODE.packageName);
writer.write("streamHasher");
},
"md5", writer -> {
writer.addDependency(TypeScriptDependency.AWS_SDK_TYPES);
writer.addImport("HashConstructor", "__HashConstructor",
TypeScriptDependency.AWS_SDK_TYPES.packageName);
writer.write("Hash.bind(null, \"md5\")");
},
"sha1", writer -> {
writer.addDependency(TypeScriptDependency.AWS_SDK_TYPES);
writer.addImport("HashConstructor", "__HashConstructor",
TypeScriptDependency.AWS_SDK_TYPES.packageName);
writer.write("Hash.bind(null, \"sha1\")");
}
);
case BROWSER:
return MapUtils.of(
"streamHasher", writer -> {
writer.addDependency(TypeScriptDependency.STREAM_HASHER_BROWSER);
writer.addImport("blobHasher", "streamHasher",
TypeScriptDependency.STREAM_HASHER_BROWSER.packageName);
writer.write("streamHasher");
},
"md5", writer -> {
writer.addDependency(TypeScriptDependency.MD5_BROWSER);
writer.addImport("Md5", "Md5", TypeScriptDependency.MD5_BROWSER.packageName);
writer.write("Md5");
},
"sha1", writer -> {
writer.addDependency(AwsDependency.AWS_CRYPTO_SHA1_BROWSER);
writer.addImport("Sha1",
"Sha1", AwsDependency.AWS_CRYPTO_SHA1_BROWSER.packageName);
writer.write("Sha1");
}
);
default:
return Collections.emptyMap();
}
}

@Override
public List<RuntimeClientPlugin> getClientPlugins() {
return ListUtils.of(
RuntimeClientPlugin.builder()
.withConventions(AwsDependency.FLEXIBLE_CHECKSUMS_MIDDLEWARE.dependency, "FlexibleChecksums",
HAS_MIDDLEWARE)
.additionalPluginFunctionParamsSupplier((m, s, o) -> getPluginFunctionParams(m, s, o))
.operationPredicate((m, s, o) -> hasHttpChecksumTrait(o))
.build()
);
}

private static Map<String, Object> getPluginFunctionParams(
Model model,
ServiceShape service,
OperationShape operation
) {
Map<String, Object> params = new TreeMap<String, Object>();
params.put("input", Symbol.builder().name("this.input").build());

HttpChecksumTrait httpChecksumTrait = operation.expectTrait(HttpChecksumTrait.class);
params.put("requestChecksumRequired", httpChecksumTrait.isRequestChecksumRequired());
httpChecksumTrait.getRequestAlgorithmMember().ifPresent(requestAlgorithmMember -> {
params.put("requestAlgorithmMember", requestAlgorithmMember);
});
httpChecksumTrait.getRequestValidationModeMember().ifPresent(requestValidationModeMember -> {
params.put("requestValidationModeMember", requestValidationModeMember);
params.put("responseAlgorithms", httpChecksumTrait.getResponseAlgorithms());
});

return params;
}

// return true if operation shape is decorated with `httpChecksum` trait.
private static boolean hasHttpChecksumTrait(OperationShape operation) {
return operation.hasTrait(HttpChecksumTrait.class);
}

private static boolean hasHttpChecksumTrait(
Model model,
ServiceShape service
) {
TopDownIndex topDownIndex = TopDownIndex.of(model);
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
for (OperationShape operation : operations) {
if (hasHttpChecksumTrait(operation)) {
return true;
}
}
return false;
}
}
Expand Up @@ -70,7 +70,9 @@ public enum AwsDependency implements SymbolDependencyContainer {
MIDDLEWARE_USER_AGENT("dependencies", "@aws-sdk/middleware-user-agent"),
AWS_SDK_UTIL_USER_AGENT_BROWSER(NORMAL_DEPENDENCY, "@aws-sdk/util-user-agent-browser"),
AWS_SDK_UTIL_USER_AGENT_NODE(NORMAL_DEPENDENCY, "@aws-sdk/util-user-agent-node"),
MIDDLEWARE_ENDPOINT_DISCOVERY(NORMAL_DEPENDENCY, "@aws-sdk/middleware-endpoint-discovery");
MIDDLEWARE_ENDPOINT_DISCOVERY(NORMAL_DEPENDENCY, "@aws-sdk/middleware-endpoint-discovery"),
AWS_CRYPTO_SHA1_BROWSER(NORMAL_DEPENDENCY, "@aws-crypto/sha1-browser", "2.0.0"),
FLEXIBLE_CHECKSUMS_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-flexible-checksums");

public final String packageName;
public final String version;
Expand Down
Expand Up @@ -20,4 +20,5 @@ software.amazon.smithy.aws.typescript.codegen.AddOmitRetryHeadersDependency
software.amazon.smithy.aws.typescript.codegen.StripNewEnumNames
software.amazon.smithy.aws.typescript.codegen.AddCrossRegionCopyingPlugin
software.amazon.smithy.aws.typescript.codegen.AddDocumentClientPlugin
software.amazon.smithy.aws.typescript.codegen.AddEndpointDiscoveryPlugin
software.amazon.smithy.aws.typescript.codegen.AddEndpointDiscoveryPlugin
software.amazon.smithy.aws.typescript.codegen.AddHttpChecksumDependency