Git Product home page Git Product logo

Comments (7)

tuanardouin avatar tuanardouin commented on September 9, 2024 3

I'm also trying to use websocket with CDK. Your code helped me a lot !

I created this repository if you want :

https://github.com/tuanardouin/WebSocket-CDK

from simple-websockets-chat-app.

mrpackethead avatar mrpackethead commented on September 9, 2024 2

There is a bug / error in the Boto3 documentation!!!!! The boto3 client docs dont' say how to specifiy the url! I foudn this issue in the boto github issues, its been an issue for nearly 2 years with multiple people hitting the same issue! Minor change to the lambda...

My problem is resolved.

import boto3
import os
from botocore.exceptions import ClientError
import json


def lambda_handler(event, context):

    message = 'one two three'
    print(event)
    
    connectionId = event['requestContext']['connectionId']
    print(connectionId)
    
    url = 'https://' + event['requestContext']['domainName'] + '/prod'
    
    api_client = boto3.client('apigatewaymanagementapi', endpoint_url=url)
    api_client.post_to_connection(
            Data = message,
            ConnectionId = connectionId
    )

    return {    
            'statusCode': 200, 
            'body': 'Message Sent' 
    }```

from simple-websockets-chat-app.

mrpackethead avatar mrpackethead commented on September 9, 2024

this is the cdk code so far...

from aws_cdk import (
    aws_cloudformation as cfn,
    aws_logs as cwlogs,
    aws_lambda,
    aws_lambda_python as py_lambda,
    aws_apigatewayv2 as apiv2,
    aws_iam as iam,
    aws_route53 as r53,
    aws_certificatemanager as acm,
    aws_dynamodb as dynamodb,
    core,
)


class WebsocketStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        brand = 'a'
        stage = 'dev'
        tablename = 'webchat'

        connectionstable = dynamodb.Table(self, 'connectionsTable',
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            removal_policy=core.RemovalPolicy.DESTROY,
            table_name = tablename,
            partition_key=dynamodb.Attribute(name="connectionId", type=dynamodb.AttributeType.STRING),
        )

        websocketgw = apiv2.CfnApi(self, 'websocket',
            name =  'SimpleChatWebSocket',
            protocol_type = 'WEBSOCKET',
            route_selection_expression = '$request.body.action'
        )

        # connect function
        connect_function =  py_lambda.PythonFunction(self, "connect_function",
            entry= 'websocket/api_lambda/connect',                            #folder
            index = 'connect.py',                           #file
            handler = 'lambda_handler',                 #function
            description = 'connect',
            environment = {
                'brand':brand,
                'stage':stage,
                'tablename': tablename},
            timeout = core.Duration.seconds(60)
        )

        connect_function_policy = iam.Policy(self, 'connect_policy',
            statements= [
                iam.PolicyStatement(
                    actions = ['dynamodb:*'],
                    resources = [connectionstable.table_arn]  
                )
            ],
            roles= [connect_function.role]
        )

        connect_function_permission = aws_lambda.CfnPermission(self, 'connectFunctionPermission',
            action = 'lambda:InvokeFunction',
            function_name = connect_function.function_name,
            principal = 'apigateway.amazonaws.com'
        )
        connect_function_permission.add_depends_on(websocketgw)


        # disconnect function
        disconnect_function =  py_lambda.PythonFunction(self, "disconnect_function",
            entry= 'websocket/api_lambda/disconnect',                            #folder
            index = 'disconnect.py',                           #file
            handler = 'lambda_handler',                 #function
            description = 'disconnect',
            environment = {
                'brand':brand,
                'stage':stage,
                'tablename': tablename},
            timeout = core.Duration.seconds(60)
        )

        disconnect_function_policy = iam.Policy(self, 'disconnect_policy',
            statements= [
                iam.PolicyStatement(
                    actions = ['dynamodb:*'],
                    resources = [connectionstable.table_arn]  
                )
            ],
            roles= [disconnect_function.role]
        )

        disconnect_function_permission = aws_lambda.CfnPermission(self, 'disconnectFunctionPermission',
            action = 'lambda:InvokeFunction',
            function_name = disconnect_function.function_name,
            principal = 'apigateway.amazonaws.com'
        )
        disconnect_function_permission.add_depends_on(websocketgw)

        #send message function.
        sendmessage_function =  py_lambda.PythonFunction(self, "sendmessage_function",
            entry= 'websocket/api_lambda/sendmessage',                            #folder
            index = 'sendmessage.py',                                             #file
            handler = 'lambda_handler',                                           #function
            description = 'sendmessage',
            environment = {
                'brand':brand,
                'stage':stage,
                'tablename': tablename},
            timeout = core.Duration.seconds(60)
        )
        sendmessage_function_policy = iam.Policy(self, 'sendmessage_policy',
            statements= [
                iam.PolicyStatement(
                    actions = ['dynamodb:*'],
                    resources = [connectionstable.table_arn]  
                ),
                iam.PolicyStatement(
                    actions = ['execute-api:ManageConnections'],
                    resources= [f'arn:aws:execute-api:aws:{self.region}:{self.account}:{websocketgw.ref}/*'],
                ),
            ],
            roles= [sendmessage_function.role]        
        )
        sendmessage_function_permission = aws_lambda.CfnPermission(self, 'sendmessageFunctionPermission',
            action = 'lambda:InvokeFunction',
            function_name = sendmessage_function.function_name,
            principal = 'apigateway.amazonaws.com'
        )
        connect_function_permission.add_depends_on(websocketgw)


        # Connect route
        connect_integration = apiv2.CfnIntegration(self, 'ConnectIntegration',
            api_id = websocketgw.ref,
            description= 'Connect Integration',
            integration_type = 'AWS_PROXY',
            integration_uri = f'arn:aws:apigateway:{self.region}:lambda:path/2015-03-31/functions/{connect_function.function_arn}/invocations'
        )  
        
        connect_route = apiv2.CfnRoute(self, 'connectRoute',
            api_id = websocketgw.ref,
            route_key = '$connect',
            authorization_type = 'NONE',
            operation_name = 'ConnectRoute',
            target = 'integrations/' + connect_integration.ref 
        )

        #Disconnect route
        disconnect_integration = apiv2.CfnIntegration(self, 'disConnectIntegration',
            api_id = websocketgw.ref,
            description= 'disConnect Integration',
            integration_type = 'AWS_PROXY',
            integration_uri = f'arn:aws:apigateway:{self.region}:lambda:path/2015-03-31/functions/{disconnect_function.function_arn}/invocations'

        ) 
        disconnect_route = apiv2.CfnRoute(self, 'disconnectRoute',
            api_id = websocketgw.ref,
            route_key = '$disconnect',
            authorization_type = 'NONE',
            operation_name = 'DisconnectRoute',
            target = 'integrations/' + disconnect_integration.ref 
        )

        #Send Route
        sendmessage_integration = apiv2.CfnIntegration(self, 'sendMessageIntegration',
            api_id = websocketgw.ref,
            description= 'sendmessage Integration',
            integration_type = 'AWS_PROXY',
            integration_uri = f'arn:aws:apigateway:{self.region}:lambda:path/2015-03-31/functions/{sendmessage_function.function_arn}/invocations'
        ) 
        sendmessage_route = apiv2.CfnRoute(self, 'sendRoute',
            api_id = websocketgw.ref,
            route_key = 'sendmessage',
            authorization_type = 'NONE',
            operation_name = 'SendRoute',
            target = 'integrations/' + sendmessage_integration.ref 
        )

        
        
        deployment = apiv2.CfnDeployment(self, 'Deployment',
            api_id = websocketgw.ref,
        )
        deployment.add_depends_on(sendmessage_route)
        deployment.add_depends_on(connect_route)
        deployment.add_depends_on(disconnect_route)
        
        

        stage = apiv2.CfnStage(self, 'stage',
            stage_name= 'prod',
            description= 'prod stage',
            deployment_id= deployment.ref,
            api_id = websocketgw.ref,
        )

        core.CfnOutput(self,'WebSocketURI',
            value = f'wss://{websocketgw.ref}.execute-api.{self.region}.amazonaws.com/prod',
            description = 'URI of websocket'
        )



        print('WebSocket')

from simple-websockets-chat-app.

mrpackethead avatar mrpackethead commented on September 9, 2024

I suspect that boto is possibly not working nicely. If we look carefully at the URL that it is tryign to send to, we see its

"https://execute-api.ap-southeast-2.amazonaws.com/@connections/VNmugd9KSwMCFwQ%3D"

Its missing the id of the API gateway.

Boto3 doesnt provide a parameter for the URL.

from simple-websockets-chat-app.

mrpackethead avatar mrpackethead commented on September 9, 2024

That boto3 documentation bug is really annoying! I've finished my pattern now, but glad that it helped you out.

from simple-websockets-chat-app.

vbabaria avatar vbabaria commented on September 9, 2024

Thanks for sharing your work, how do you test python code locally before pushing it out to AWS? - thanks

from simple-websockets-chat-app.

dgomesbr avatar dgomesbr commented on September 9, 2024

Thanks for this. Closing for history.

from simple-websockets-chat-app.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.