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(middleware-sdk-rekognitionstreaming): create port middleware #4622

Merged
merged 2 commits into from
Apr 6, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clients/client-rekognitionstreaming/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@aws-sdk/middleware-logger": "*",
"@aws-sdk/middleware-recursion-detection": "*",
"@aws-sdk/middleware-retry": "*",
"@aws-sdk/middleware-sdk-rekognitionstreaming": "*",
"@aws-sdk/middleware-serde": "*",
"@aws-sdk/middleware-signing": "*",
"@aws-sdk/middleware-stack": "*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import { getLoggerPlugin } from "@aws-sdk/middleware-logger";
import { getRecursionDetectionPlugin } from "@aws-sdk/middleware-recursion-detection";
import { getRetryPlugin, resolveRetryConfig, RetryInputConfig, RetryResolvedConfig } from "@aws-sdk/middleware-retry";
import { getRekognitionStreamingPlugin } from "@aws-sdk/middleware-sdk-rekognitionstreaming";
import {
AwsAuthInputConfig,
AwsAuthResolvedConfig,
Expand Down Expand Up @@ -319,6 +320,7 @@ export class RekognitionStreamingClient extends __Client<
this.middlewareStack.use(getLoggerPlugin(this.config));
this.middlewareStack.use(getRecursionDetectionPlugin(this.config));
this.middlewareStack.use(getAwsAuthPlugin(this.config));
this.middlewareStack.use(getRekognitionStreamingPlugin(this.config));
this.middlewareStack.use(getUserAgentPlugin(this.config));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

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

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import software.amazon.smithy.aws.traits.ServiceTrait;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.typescript.codegen.LanguageTarget;
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.SmithyInternalApi;

/**
* Add client plugins and configs to support WebSocket streaming for Rekognition
* Streaming service.
**/
@SmithyInternalApi
public class AddRekognitionStreamingDependency implements TypeScriptIntegration {
@Override
public List<RuntimeClientPlugin> getClientPlugins() {
return ListUtils.of(
RuntimeClientPlugin.builder()
.withConventions(AwsDependency.REKOGNITION_STREAMING_MIDDLEWARE.dependency,
"RekognitionStreaming", RuntimeClientPlugin.Convention.HAS_MIDDLEWARE)
.servicePredicate((m, s) -> isRekognitionStreaming(s))
.build()
);
}

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

switch (target) {
case REACT_NATIVE:
case BROWSER:
default:
return Collections.emptyMap();
}
}

private static boolean isRekognitionStreaming(ServiceShape service) {
String serviceId = service.getTrait(ServiceTrait.class).map(ServiceTrait::getSdkId).orElse("");
return serviceId.equals("RekognitionStreaming");
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public enum AwsDependency implements SymbolDependencyContainer {
MIDDLEWARE_EVENTSTREAM(NORMAL_DEPENDENCY, "@aws-sdk/middleware-eventstream"),
AWS_SDK_EVENTSTREAM_HANDLER_NODE(NORMAL_DEPENDENCY, "@aws-sdk/eventstream-handler-node"),
TRANSCRIBE_STREAMING_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-transcribe-streaming"),
REKOGNITION_STREAMING_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-rekognitionstreaming"),
STS_MIDDLEWARE(NORMAL_DEPENDENCY, "@aws-sdk/middleware-sdk-sts"),
STS_CLIENT(NORMAL_DEPENDENCY, "@aws-sdk/client-sts"),
MIDDLEWARE_LOGGER(NORMAL_DEPENDENCY, "@aws-sdk/middleware-logger"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ software.amazon.smithy.aws.typescript.codegen.AddEventStreamHandlingDependency
software.amazon.smithy.aws.typescript.codegen.AddHttp2Dependency
software.amazon.smithy.aws.typescript.codegen.AddWebsocketPlugin
software.amazon.smithy.aws.typescript.codegen.AddTranscribeStreamingDependency
software.amazon.smithy.aws.typescript.codegen.AddRekognitionStreamingDependency
software.amazon.smithy.aws.typescript.codegen.AddUserAgentDependency
software.amazon.smithy.aws.typescript.codegen.AddOmitRetryHeadersDependency
software.amazon.smithy.aws.typescript.codegen.StripNewEnumNames
Expand Down
9 changes: 9 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/node_modules/
/build/
/dist/
/coverage/
/docs/
*.tsbuildinfo
*.tgz
*.log
package-lock.json
Empty file.
4 changes: 4 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# @aws-sdk/middleware-sdk-rekognitionstreaming

[![NPM version](https://img.shields.io/npm/v/@aws-sdk/middleware-sdk-rekognitionstreaming/latest.svg)](https://www.npmjs.com/package/@aws-sdk/middleware-sdk-rekognitionstreaming)
[![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/middleware-sdk-rekognitionstreaming.svg)](https://www.npmjs.com/package/@aws-sdk/middleware-sdk-rekognitionstreaming)
7 changes: 7 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const base = require("../../jest.config.base.js");

module.exports = {
...base,
//only test cjs dist, avoid testing the package twice
testPathIgnorePatterns: ["/node_modules/", "/es/"],
};
60 changes: 60 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "@aws-sdk/middleware-sdk-rekognitionstreaming",
"version": "3.0.0",
"main": "./dist-cjs/index.js",
"module": "./dist-es/index.js",
"types": "./dist-types/index.d.ts",
"scripts": {
"build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
"build:cjs": "tsc -p tsconfig.cjs.json",
"build:es": "tsc -p tsconfig.es.json",
"build:include:deps": "lerna run --scope $npm_package_name --include-dependencies build",
"build:types": "tsc -p tsconfig.types.json",
"build:types:downlevel": "downlevel-dts dist-types dist-types/ts3.4",
"clean": "rimraf ./dist-* && rimraf *.tsbuildinfo",
"test": "jest --passWithNoTests"
},
"author": {
"name": "AWS SDK for JavaScript Team",
"url": "https://aws.amazon.com/javascript/"
},
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/protocol-http": "*",
"@aws-sdk/types": "*",
"tslib": "^2.5.0"
},
"devDependencies": {
"@tsconfig/recommended": "1.0.1",
"@types/uuid": "^8.3.0",
"concurrently": "7.0.0",
"downlevel-dts": "0.10.1",
"jest-websocket-mock": "^2.0.2",
"mock-socket": "9.1.5",
"rimraf": "3.0.2",
"typedoc": "0.23.23",
"typescript": "~4.9.5"
},
"engines": {
"node": ">=14.0.0"
},
"typesVersions": {
"<4.0": {
"dist-types/*": [
"dist-types/ts3.4/*"
]
}
},
"files": [
"dist-*"
],
"homepage": "https://github.com/aws/aws-sdk-js-v3/tree/main/packages/middleware-sdk-rekognitionstreaming",
"repository": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-js-v3.git",
"directory": "packages/middleware-sdk-rekognitionstreaming"
},
"typedoc": {
"entryPoint": "src/index.ts"
}
}
2 changes: 2 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./middleware-port";
export * from "./plugin";
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { HttpRequest } from "@aws-sdk/protocol-http";
import { BuildHandlerArguments, RequestHandler } from "@aws-sdk/types";

import { websocketPortMiddleware } from "./middleware-port";

describe("websocketPortMiddleware", () => {
const mockHandler: RequestHandler<any, any> = {
metadata: { handlerProtocol: "websocket" },
handle: () => ({} as any),
};
it("should skip non-http request", (done) => {
const nonHttpRequest = {
foo: "bar",
};
const next = (args: BuildHandlerArguments<any>) => {
expect(args.request).toEqual(nonHttpRequest);
done();
};
const mw = websocketPortMiddleware({ requestHandler: mockHandler });
mw(next as any, {} as any)({ request: nonHttpRequest, input: {} });
});

it("should skip non WebSocket requests", (done) => {
const mockHandler: RequestHandler<any, any> = {
metadata: { handlerProtocol: "some_protocol" },
handle: () => ({} as any),
};
const request = new HttpRequest({});
const next = (args: BuildHandlerArguments<any>) => {
expect(args.request).toEqual(request);
done();
};
const mw = websocketPortMiddleware({ requestHandler: mockHandler });
mw(next as any, {} as any)({ request, input: {} });
});

it("should update endpoint to websocket url", (done) => {
const request = new HttpRequest({
hostname: "streaming-rekognition.us-east-1.amazonaws.com",
});
const next = (args: BuildHandlerArguments<any>) => {
expect(HttpRequest.isInstance(args.request)).toBeTruthy();
const processed = args.request as HttpRequest;
expect(processed.hostname).toEqual("streaming-rekognition.us-east-1.amazonaws.com:443");
expect(processed.headers.host).toEqual("streaming-rekognition.us-east-1.amazonaws.com:443");
done();
};
const mw = websocketPortMiddleware({ requestHandler: mockHandler });
mw(next as any, {} as any)({ request, input: {} });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { HttpRequest } from "@aws-sdk/protocol-http";
import {
BuildHandler,
BuildHandlerArguments,
BuildMiddleware,
RelativeMiddlewareOptions,
RequestHandler,
} from "@aws-sdk/types";

/**
* @internal
*
* Middleware that generates WebSocket URL to RekognitionStreaming service
* Reference: https://docs.aws.amazon.com/transcribe/latest/dg/websocket.html
*/
export const websocketPortMiddleware =
(options: { requestHandler: RequestHandler<any, any> }): BuildMiddleware<any, any> =>
(next: BuildHandler<any, any>) =>
(args: BuildHandlerArguments<any>) => {
const { request } = args;
if (HttpRequest.isInstance(request) && options.requestHandler.metadata?.handlerProtocol?.includes("websocket")) {
// Append port to hostname because it needs to be signed together
request.hostname = `${request.hostname}:443`;
request.headers.host = request.hostname;
}
return next(args);
};

/**
* @internal
*/
export const websocketPortMiddlewareOptions: RelativeMiddlewareOptions = {
name: "websocketPortMiddleware",
tags: ["WEBSOCKET", "EVENT_STREAM", "PORT"],
relation: "after",
toMiddleware: "eventStreamHeaderMiddleware",
override: true,
};
16 changes: 16 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Pluggable, RequestHandler } from "@aws-sdk/types";

import { websocketPortMiddleware, websocketPortMiddlewareOptions } from "./middleware-port";

interface PreviouslyResolved {
requestHandler: RequestHandler<any, any>;
}

/**
* @internal
*/
export const getRekognitionStreamingPlugin = (config: PreviouslyResolved): Pluggable<any, any> => ({
applyToStack: (clientStack) => {
clientStack.addRelativeTo(websocketPortMiddleware(config), websocketPortMiddlewareOptions);
},
});
10 changes: 10 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/tsconfig.cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"outDir": "dist-cjs",
"rootDir": "src",
"stripInternal": true
},
"extends": "../../tsconfig.cjs.json",
"include": ["src/"]
}
11 changes: 11 additions & 0 deletions packages/middleware-sdk-rekognitionstreaming/tsconfig.es.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"baseUrl": ".",
"lib": ["DOM"],
"outDir": "dist-es",
"rootDir": "src",
"stripInternal": true
},
"extends": "../../tsconfig.es.json",
"include": ["src/"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
"declarationDir": "dist-types",
"rootDir": "src"
},
"extends": "../../tsconfig.types.json",
"include": ["src/"]
}