AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > Backend for Websockets (including functions) Globals: Function: Layers: - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:5 - !Sub arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:14 Runtime: nodejs18.x Handler: app.handler MemorySize: 512 Timeout: 10 Tracing: Active Environment: Variables: AWS_EMF_NAMESPACE: !Sub "${EMFNamespace}" Parameters: EMFNamespace: Type: String Description: Name of the EMF Namespace Default: "STS" LogRetentionDays: Type: Number Description: CloudWatch Log Retention Days Default: 7 ResourceGroupPrefix: Type: String Description: Name of the ResourceGroup for resources in this template Default: "GameService" Resources: ResourceGroup: Type: "AWS::ResourceGroups::Group" Properties: Name: !Join ["-", [!Sub "${ResourceGroupPrefix}", "WS"]] WebSocket: Type: AWS::ApiGatewayV2::Api Properties: Name: WebSocket ProtocolType: WEBSOCKET RouteSelectionExpression: "$request.body.message" ConnectRoute: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref WebSocket RouteKey: $connect AuthorizationType: CUSTOM AuthorizerId: !Ref WSAuthorizer OperationName: ConnectRoute DisconnectRoute: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref WebSocket RouteKey: $disconnect AuthorizationType: NONE OperationName: DisconnectRoute Target: !Join - '/' - - 'integrations' - !Ref DisconnectInteg DisconnectInteg: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref WebSocket Description: Disconnect Integration IntegrationType: AWS_PROXY TimeoutInMillis: 5000 IntegrationUri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnDisconnectFunction.Arn}/invocations LiveGameAdminRoute: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref WebSocket RouteKey: liveadmin AuthorizationType: NONE OperationName: LiveAdminRoute Target: !Join - '/' - - 'integrations' - !Ref LiveGameAdminInteg LiveGameAdminInteg: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref WebSocket Description: LiveGameAdmin Integration IntegrationType: AWS_PROXY TimeoutInMillis: 5000 IntegrationUri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LiveGameAdminFunction.Arn}/invocations LiveGamePlayerRoute: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref WebSocket RouteKey: liveplayer AuthorizationType: NONE OperationName: LivePlayerRoute Target: !Sub 'integrations/${LiveGamePlayerInteg}' LiveGamePlayerInteg: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref WebSocket Description: LiveGamePlayer Integration TimeoutInMillis: 5000 IntegrationType: AWS_PROXY IntegrationUri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LiveGamePlayerFunction.Arn}/invocations WebSocketDeployment: Type: AWS::ApiGatewayV2::Deployment DependsOn: - ConnectRoute - DisconnectRoute - LiveGamePlayerRoute - LiveGameAdminRoute - WSAuthorizer Properties: ApiId: !Ref WebSocket WebSocketStage: Type: AWS::ApiGatewayV2::Stage Properties: StageName: Prod Description: Prod Stage DeploymentId: !Ref WebSocketDeployment ApiId: !Ref WebSocket Tags: Dashboard: WebSocket OnDisconnectFunction: Type: AWS::Serverless::Function Properties: AutoPublishAlias: Live CodeUri: functions/ondisconnect/ Environment: Variables: GAME_PLAYERS_TABLE_NAME: !ImportValue STS-GamePlayersTable REGION: !Sub ${AWS::Region} Policies: - DynamoDBCrudPolicy: TableName: !ImportValue STS-GamePlayersTable - CloudWatchLambdaInsightsExecutionRolePolicy Tags: Dashboard: WebSocket Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" Sourcemap: true EntryPoints: - app.ts OnDisconnectFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: 14 LogGroupName: !Join ["", ["/aws/lambda/", !Ref OnDisconnectFunction]] OnDisconnectPermission: Type: AWS::Lambda::Permission DependsOn: - WebSocket - OnDisconnectFunction Properties: Action: lambda:InvokeFunction FunctionName: !Ref OnDisconnectFunction Principal: apigateway.amazonaws.com # OnDisconnectVersion: # Type: AWS::Lambda::Version # Properties: # FunctionName: !Ref OnDisconnectFunction # OnDisconnectAlias: # Type: AWS::Lambda::Alias # Properties: # FunctionName: !Ref OnDisconnectFunction # FunctionVersion: !GetAtt OnDisconnectVersion.Version # Name: Live AuthorizerFunction: Type: AWS::Serverless::Function Properties: AutoPublishAlias: Live CodeUri: functions/auth/ Environment: Variables: REGION: !Sub "${AWS::Region}" POOL_ID: !ImportValue STS-UserPoolId APPCLIENTID: !ImportValue STS-AppClientId API_ID: !Ref WebSocket STAGE: Prod Tags: Dashboard: WebSocket Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" Sourcemap: true EntryPoints: - app.ts AuthorizerFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: !Sub "${LogRetentionDays}" LogGroupName: !Join ["", ["/aws/lambda/", !Ref AuthorizerFunction]] # AuthorizerVersion: # Type: AWS::Lambda::Version # Properties: # FunctionName: !Ref AuthorizerFunction # AuthorizerAlias: # Type: AWS::Lambda::Alias # Properties: # FunctionName: !Ref AuthorizerFunction # FunctionVersion: !GetAtt AuthorizerVersion.Version # Name: Live AuthorizerPermissions: Type: AWS::Lambda::Permission DependsOn: - WebSocket - AuthorizerFunction Properties: Action: lambda:InvokeFunction FunctionName: !Ref AuthorizerFunction Principal: apigateway.amazonaws.com WSAuthorizer: Type: AWS::ApiGatewayV2::Authorizer Properties: AuthorizerType: REQUEST ApiId: !Ref WebSocket IdentitySource: - route.request.querystring.access_token AuthorizerUri: !Join - '' - - "arn:aws:apigateway:" - !Sub ${AWS::Region} - ":lambda:path/2015-03-31/functions/" - !GetAtt AuthorizerFunction.Arn - "/invocations" Name: WSAuth LiveGamePlayerFunction: Type: AWS::Serverless::Function Properties: AutoPublishAlias: Live CodeUri: functions/livegameplayer/ MemorySize: 1536 Environment: Variables: PLAYER_INVENTORY_TABLE_NAME: !ImportValue STS-PlayerInventoryTable PLAYERS_TABLE_NAME: !ImportValue STS-GamePlayersTable EVENT_BUS_NAME: !ImportValue STS-STSEventBusName REGION: !Sub "${AWS::Region}" Policies: - DynamoDBCrudPolicy: TableName: !ImportValue STS-GamePlayersTable - DynamoDBReadPolicy: TableName: !ImportValue STS-PlayerInventoryTable - EventBridgePutEventsPolicy: EventBusName: !ImportValue STS-STSEventBusName - !Ref WebSocketManageConnectionsPolicy - CloudWatchLambdaInsightsExecutionRolePolicy Tags: Dashboard: WebSocket Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" Sourcemap: true EntryPoints: - app.ts LiveGamePlayerLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: !Sub "${LogRetentionDays}" LogGroupName: !Join ["", ["/aws/lambda/", !Ref LiveGamePlayerFunction]] # LiveGamePlayerVersion: # Type: AWS::Lambda::Version # Properties: # FunctionName: !Ref LiveGamePlayerFunction # LiveGamePlayerAlias: # Type: AWS::Lambda::Alias # Properties: # FunctionName: !Ref LiveGamePlayerFunction # FunctionVersion: !GetAtt LiveGamePlayerVersion.Version # Name: Live LiveGamePlayerPermission: Type: AWS::Lambda::Permission DependsOn: - WebSocket - LiveGamePlayerFunction Properties: Action: lambda:InvokeFunction FunctionName: !Ref LiveGamePlayerFunction Principal: apigateway.amazonaws.com LiveGameAdminFunction: Type: AWS::Serverless::Function Properties: AutoPublishAlias: Live CodeUri: functions/livegameadmin/ MemorySize: 1536 Environment: Variables: SCORES_TABLE_NAME: !ImportValue STS-HighScoreTable PLAYERS_TABLE_NAME: !ImportValue STS-GamePlayersTable PLAYER_PROGRESS_TOPIC: !ImportValue STS-PlayerProgressTopicArn PLAYER_INVENTORY_TABLE_NAME: !ImportValue STS-PlayerInventoryTable RESPONSE_STREAM: !ImportValue STS-QuizSourceStreamName CHAT_TOPIC_ARN: !ImportValue STS-ChatTopicArn EVENT_BUS_NAME: !ImportValue STS-STSEventBusName REGION: !Sub "${AWS::Region}" Policies: - KinesisCrudPolicy: StreamName: !ImportValue STS-QuizSourceStreamName - SNSPublishMessagePolicy: TopicName: !ImportValue STS-PlayerProgressTopicName - DynamoDBCrudPolicy: TableName: !ImportValue STS-HighScoreTable - DynamoDBCrudPolicy: TableName: !ImportValue STS-GamePlayersTable - DynamoDBCrudPolicy: TableName: !ImportValue STS-PlayerInventoryTable - SNSPublishMessagePolicy: TopicName: !ImportValue STS-ChatTopicName - EventBridgePutEventsPolicy: EventBusName: !ImportValue STS-STSEventBusName - CloudWatchLambdaInsightsExecutionRolePolicy - !Ref WebSocketManageConnectionsPolicy Tags: Dashboard: WebSocket Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" Sourcemap: true EntryPoints: - app.ts LiveGameAdminFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: !Sub "${LogRetentionDays}" LogGroupName: !Join ["", ["/aws/lambda/", !Ref LiveGameAdminFunction]] LiveGameAdminPermission: Type: AWS::Lambda::Permission DependsOn: - WebSocket - LiveGameAdminFunction Properties: Action: lambda:InvokeFunction FunctionName: !Ref LiveGameAdminFunction Principal: apigateway.amazonaws.com GameDataDeleteFunction: Type: AWS::Serverless::Function Properties: AutoPublishAlias: Live CodeUri: functions/gameplayer_delete/ MemorySize: 1536 Environment: Variables: PLAYERS_TABLE_NAME: !ImportValue STS-GamePlayersTable PLAYER_INVENTORY_TABLE_NAME: !ImportValue STS-PlayerInventoryTable REGION: !Sub "${AWS::Region}" Policies: - DynamoDBCrudPolicy: TableName: !ImportValue STS-GamePlayersTable - DynamoDBCrudPolicy: TableName: !ImportValue STS-PlayerInventoryTable Events: EBEvent: Type: EventBridgeRule Properties: Pattern: detail-type: - "Websockets.game_end" RetryPolicy: MaximumRetryAttempts: 5 MaximumEventAgeInSeconds: 60 EventBusName: !ImportValue STS-STSEventBusName Tags: Dashboard: WebSocket Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" Sourcemap: true EntryPoints: - app.ts GameDataDeleteLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: !Sub "${LogRetentionDays}" LogGroupName: !Join ["", ["/aws/lambda/", !Ref GameDataDeleteFunction]] MessageSendFunction: Type: AWS::Serverless::Function Properties: AutoPublishAlias: Live CodeUri: functions/message_send/ MemorySize: 1536 Environment: Variables: PLAYERS_TABLE_NAME: !ImportValue STS-GamePlayersTable REGION: !Sub "${AWS::Region}" Policies: - DynamoDBCrudPolicy: TableName: !ImportValue STS-GamePlayersTable Tags: Dashboard: WebSocket Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" Sourcemap: true EntryPoints: - app.ts MessageSendLogGroup: Type: AWS::Logs::LogGroup Properties: RetentionInDays: !Sub "${LogRetentionDays}" LogGroupName: !Join ["", ["/aws/lambda/", !Ref MessageSendFunction]] WebSocketManageConnectionsPolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: !Join ["", [!Ref "AWS::StackName", "WebSocketManageConnectionsPolicy" ] ] PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - 'execute-api:*' Resource: - !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocket}/*' Outputs: WebSocketURI: Description: "The WSS Protocol URI to connect to" Value: !Join [ '', [ 'wss://', !Ref WebSocket, '.execute-api.',!Ref 'AWS::Region','.amazonaws.com/',!Ref 'WebSocketStage'] ] Export: Name: "STS-WSURI" WebSocketAPIGWId: Description: "ID of the API Gateway used for websockets" Value: !Ref WebSocket Stage: Description: "Stage for WS API" Value: !Ref WebSocketStage