├── .gitignore
├── LICENSE
├── README.md
├── WebRTCChat.html
├── connect_handler.py
├── disconnect_handler.py
├── on_message_handler.py
├── package-lock.json
├── package.json
├── python-packages.txt
└── serverless.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Distribution / packaging
2 | .Python
3 | env/
4 | build/
5 | develop-eggs/
6 | dist/
7 | downloads/
8 | eggs/
9 | .eggs/
10 | lib/
11 | lib64/
12 | parts/
13 | sdist/
14 | var/
15 | *.egg-info/
16 | .installed.cfg
17 | *.egg
18 | .vscode
19 | python
20 |
21 | # Serverless directories
22 | .serverless
23 |
24 | # Node Modules
25 | node_modules/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Suminda Niroshan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS Websocket Messaging
2 |
3 | > This repo contains Serverless Framework project for a simple AWS Websocket chat app
4 |
5 | ### Setup
6 |
7 | > Install required npm packages first
8 |
9 | ```shell
10 | $ npm install
11 | ```
12 |
13 | > Install Serverless Framework globally
14 |
15 | ```shell
16 | $ npm install -g serverless@1.48.2
17 | ```
18 |
19 | > Install required Python packages
20 |
21 | ```shell
22 | $ pip install -r python-packages.txt -t ./lib/python
23 | ```
24 |
25 | > Deploy into AWS
26 |
27 | ```shell
28 | $ serverless deploy --stage dev
29 | ```
--------------------------------------------------------------------------------
/WebRTCChat.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebRTC Video Chat
8 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
Tap to Change Front/Back Camera
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | Outbound Video Stats |
85 | Inbound Video Stats |
86 |
87 |
88 | |
89 | |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
544 |
545 |
--------------------------------------------------------------------------------
/connect_handler.py:
--------------------------------------------------------------------------------
1 | import json
2 | import boto3
3 | import os
4 | import time
5 |
6 | dynamodb = boto3.client('dynamodb')
7 |
8 | def handle(event, context):
9 | connectionId = event['requestContext']['connectionId']
10 |
11 | # Insert the connectionId of the connected device to the database
12 | dynamodb.put_item(TableName=os.environ['SOCKET_CONNECTIONS_TABLE_NAME'], Item={'connectionId': {'S': connectionId}, 'ttl': {'N': str(int(time.time() + 600))}})
13 |
14 | return {}
--------------------------------------------------------------------------------
/disconnect_handler.py:
--------------------------------------------------------------------------------
1 | import json
2 | import boto3
3 | import os
4 |
5 | dynamodb = boto3.client('dynamodb')
6 |
7 | def handle(event, context):
8 | connectionId = event['requestContext']['connectionId']
9 |
10 | # Delete connectionId from the database
11 | dynamodb.delete_item(TableName=os.environ['SOCKET_CONNECTIONS_TABLE_NAME'], Key={'connectionId': {'S': connectionId}})
12 |
13 | return {}
--------------------------------------------------------------------------------
/on_message_handler.py:
--------------------------------------------------------------------------------
1 | import json
2 | import boto3
3 | import os
4 |
5 | dynamodb = boto3.client('dynamodb')
6 |
7 |
8 | def handle(event, context):
9 | messageType = json.loads(event['body'])['type']
10 | messageData = json.loads(event['body'])['data']
11 | messageId = json.loads(event['body'])['id']
12 |
13 | paginator = dynamodb.get_paginator('scan')
14 |
15 | connectionIds = []
16 |
17 | apigatewaymanagementapi = boto3.client('apigatewaymanagementapi',
18 | endpoint_url = "https://" + event["requestContext"]["domainName"] + "/" + event["requestContext"]["stage"])
19 |
20 | # Retrieve all connectionIds from the database
21 | for page in paginator.paginate(TableName=os.environ['SOCKET_CONNECTIONS_TABLE_NAME']):
22 | connectionIds.extend(page['Items'])
23 |
24 | # Emit the recieved message to all the connected devices
25 | for connectionId in connectionIds:
26 | apigatewaymanagementapi.post_to_connection(
27 | Data=json.dumps({"type": messageType, "data": messageData, "id": messageId}),
28 | ConnectionId=connectionId['connectionId']['S']
29 | )
30 |
31 | return {}
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "requires": true,
3 | "lockfileVersion": 1,
4 | "dependencies": {
5 | "serverless-pseudo-parameters": {
6 | "version": "2.4.0",
7 | "resolved": "https://registry.npmjs.org/serverless-pseudo-parameters/-/serverless-pseudo-parameters-2.4.0.tgz",
8 | "integrity": "sha512-lb9R62PUFdEAbbYH7pe1wzR7vtIpa8YI8OVcQ5LlLyE0+AxWG4bwEw33X5LE8+5oLwTy57Y/EevnxKnMeyiXxw=="
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "serverless-pseudo-parameters": "2.4.0"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/python-packages.txt:
--------------------------------------------------------------------------------
1 | boto3==1.9.199
--------------------------------------------------------------------------------
/serverless.yml:
--------------------------------------------------------------------------------
1 | service: awswebrtc
2 |
3 | custom:
4 | currentStage: ${opt:stage, self:provider.stage}
5 | lambdaRunTime: python3.7
6 | socketConnectionsTableName: socketConnections-#{AWS::AccountId}-${self:custom.currentStage}
7 |
8 | provider:
9 | name: aws
10 | iamManagedPolicies:
11 | - arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
12 | runtime: ${self:custom.lambdaRunTime}
13 | versionFunctions: false
14 | region: us-west-2
15 | timeout: 29
16 |
17 | plugins:
18 | - serverless-pseudo-parameters
19 |
20 | package:
21 | individually: true
22 | exclude:
23 | - "lib/**"
24 | - "node_modules/**"
25 |
26 | functions:
27 | connectHandler:
28 | handler: connect_handler.handle
29 | events:
30 | - websocket: $connect
31 | environment:
32 | SOCKET_CONNECTIONS_TABLE_NAME: ${self:custom.socketConnectionsTableName}
33 |
34 | disconnectHandler:
35 | handler: disconnect_handler.handle
36 | events:
37 | - websocket: $disconnect
38 | environment:
39 | SOCKET_CONNECTIONS_TABLE_NAME: ${self:custom.socketConnectionsTableName}
40 |
41 | onMessageHandler:
42 | handler: on_message_handler.handle
43 | events:
44 | - websocket:
45 | route: onMessage
46 | environment:
47 | SOCKET_CONNECTIONS_TABLE_NAME: ${self:custom.socketConnectionsTableName}
48 |
49 | resources:
50 | Resources:
51 | socketConnectionsTable:
52 | Type: AWS::DynamoDB::Table
53 | DeletionPolicy: Retain
54 | Properties:
55 | TableName: ${self:custom.socketConnectionsTableName}
56 | AttributeDefinitions:
57 | - AttributeName: connectionId
58 | AttributeType: S
59 | KeySchema:
60 | - AttributeName: connectionId
61 | KeyType: HASH
62 | BillingMode: PAY_PER_REQUEST
63 | SSESpecification:
64 | SSEEnabled: true
65 | TimeToLiveSpecification:
66 | AttributeName: ttl
67 | Enabled: true
--------------------------------------------------------------------------------