diff --git a/abovevttServices/app.js b/abovevttServices/app.js index cdb68d2..1995ffd 100644 --- a/abovevttServices/app.js +++ b/abovevttServices/app.js @@ -1,330 +1,184 @@ -// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 - -const AWS = require('aws-sdk'); -const { request } = require('http'); - -const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10', region: process.env.AWS_REGION }); - - -async function getAllData(params){ - const _getAllData = async (params, startKey) => { - if (startKey) { - params.ExclusiveStartKey = startKey - } - return this.documentClient.query(params).promise() - } - let lastEvaluatedKey = null - let rows = [] - do { - const result = await _getAllData(params, lastEvaluatedKey) - rows = rows.concat(result.Items) - lastEvaluatedKey = result.LastEvaluatedKey - } while (lastEvaluatedKey) - return rows -} - - - - - +const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); +const { DynamoDBDocumentClient, GetCommand, PutCommand, QueryCommand, BatchWriteCommand } = require('@aws-sdk/lib-dynamodb'); +const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({ region: process.env.AWS_REGION })); exports.handler = async event => { - - const action=event.queryStringParameters?event.queryStringParameters.action:""; + const action = event.queryStringParameters ? event.queryStringParameters.action : ""; - if(action=="getCampaignData"){ - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - return ddb.get({ + if (action == "getCampaignData") { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; + return ddb.send(new GetCommand({ TableName: process.env.TABLE_NAME, - Key: { - campaignId: campaignId, - objectId: 'campaigndata' - } - }).promise().catch(function(){ + Key: { campaignId, objectId: 'campaigndata' }, + })).catch(function () { return {}; }); } - if(action=="setCampaignData"){ - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; + if (action == "setCampaignData") { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; console.log("logging full event diocane"); console.log(event); - const campaignData=JSON.parse(event.body); + const campaignData = JSON.parse(event.body); - return ddb.put({ + return ddb.send(new PutCommand({ TableName: process.env.TABLE_NAME, Item: { - campaignId: campaignId, + campaignId, objectId: "campaigndata", data: campaignData, timestamp: Date.now(), - } - }).promise(); + }, + })); } - if(action=="migrate"){ + + if (action == "migrate") { console.log("GOT A MIGRATION REQUEST!"); - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - const scenes=JSON.parse(event.body); + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; + const scenes = JSON.parse(event.body); console.log(scenes); - let requests=[]; + let requests = []; - let nextorder=1000000; - let nextid=100; + let nextorder = 1000000; + let nextid = 100; scenes.forEach(scene => { - let fogData=scene.reveals; - let drawData=scene.drawings; - let tokens=scene.tokens; - scene.reveals=[]; - scene.drawings=[]; - scene.tokens={}; - - if(!scene.order){ - scene.order=nextorder; - nextorder=nextorder+1000000; + const fogData = scene.reveals; + const drawData = scene.drawings; + const tokens = scene.tokens; + scene.reveals = []; + scene.drawings = []; + scene.tokens = {}; + + if (!scene.order) { + scene.order = nextorder; + nextorder = nextorder + 1000000; } - if(!scene.id){ - scene.id="migrated"+nextid; - nextid=nextid+100; + if (!scene.id) { + scene.id = "migrated" + nextid; + nextid = nextid + 100; } - requests.push({ - PutRequest: { - Item: { - campaignId: campaignId, - objectId: "scenes#"+scene.id+"#scenedata", - sceneId: scene.id, - data:scene, - timestamp: Date.now(), - } - } - }); - - requests.push({ - PutRequest: { - Item: { - campaignId: campaignId, - objectId: "scenes#"+scene.id+"#fogdata", - data:fogData, - timestamp: Date.now(), - } - } - }); + requests.push({ PutRequest: { Item: { campaignId, objectId: "scenes#" + scene.id + "#scenedata", sceneId: scene.id, data: scene, timestamp: Date.now() } } }); + requests.push({ PutRequest: { Item: { campaignId, objectId: "scenes#" + scene.id + "#fogdata", data: fogData, timestamp: Date.now() } } }); + requests.push({ PutRequest: { Item: { campaignId, objectId: "scenes#" + scene.id + "#drawdata", data: drawData, timestamp: Date.now() } } }); - requests.push({ - PutRequest: { - Item: { - campaignId: campaignId, - objectId: "scenes#"+scene.id+"#drawdata", - data:drawData, - timestamp: Date.now(), - } - } - }); - - for( tokenid in tokens){ - requests.push({ - PutRequest: { - Item: { - campaignId: campaignId, - objectId: "scenes#"+scene.id+"#tokens#"+tokenid, - data:tokens[tokenid], - timestamp: Date.now(), - } - } - }); + for (const tokenid in tokens) { + requests.push({ PutRequest: { Item: { campaignId, objectId: "scenes#" + scene.id + "#tokens#" + tokenid, data: tokens[tokenid], timestamp: Date.now() } } }); } }); - // and finally enable the cloud ! - requests.push({ - PutRequest: { - Item: { - campaignId: campaignId, - objectId: "campaigndata", - data:{ - cloud:1 - }, - timestamp: Date.now(), - } - } - }); + requests.push({ PutRequest: { Item: { campaignId, objectId: "campaigndata", data: { cloud: 1 }, timestamp: Date.now() } } }); console.log("preparing the batch writes"); - // NOW SEND THE REQUESTS with a super batch write - let promises=[]; - for(let i=0;i{console.log(results);} - ); + await Promise.allSettled(promises).then((results) => { console.log(results); }); + + return { statusCode: 200, body: 'Migrated' }; + } - return { statusCode: 200, body: 'Migrated' }; - } // END OF MIGRATE + if (action == "export_scenes") { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; - if(action=="export_scenes"){ - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - const queryParams ={ + const queryReply = await ddb.send(new QueryCommand({ TableName: process.env.TABLE_NAME, IndexName: 'sceneProperties', KeyConditionExpression: "campaignId = :hkey", - ExpressionAttributeValues: { - ':hkey': campaignId, - }, - }; - - return ddb.query(queryParams).promise().then((queryReply)=>{ - let export_data=[]; - let scenelist=queryReply.Items.map( (element)=> element.data); - - let promises=[]; - scenelist.forEach( - (scene)=>{ - - let sceneId=scene.id; - scene.tokens={}; - scene.reveals=[]; - scene.drawings=[]; - let readScenePromise=ddb.query({ - TableName: process.env.TABLE_NAME, - KeyConditionExpression: "campaignId = :hkey and begins_with(objectId,:skey)", - ExpressionAttributeValues: { - ':hkey': campaignId, - ':skey': "scenes#"+sceneId - }, - }).promise().then( - (sceneObjects)=>{ // this contains all tokens, reveals etc etc. we pack it in the scene - // add tokens to scene - console.log("got those sceneObjects"); - console.log(sceneObjects); - console.log("for this scene"); - console.log(scene); - sceneObjects.Items.filter( (element)=> element.objectId.startsWith("scenes#"+sceneId+"#tokens#")).forEach((element)=>scene.tokens[element.data.id]=element.data); - - // add fog - let fogdata=sceneObjects.Items.find((element) => element.objectId=="scenes#"+sceneId+"#fogdata"); - if(fogdata && fogdata.data) - scene.reveals=fogdata.data; - console.log("got this fog"); - console.log(fogdata); - let drawdata=sceneObjects.Items.find((element) => element.objectId=="scenes#"+sceneId+"#drawdata"); - - if(drawdata && drawdata.data) - scene.drawings=drawdata.data; - - export_data.push(scene); - }); - promises.push(readScenePromise); - } - ); - - return Promise.allSettled(promises).then( - ()=>{ - return { statusCode: 200, body: JSON.stringify(export_data) }; - } - ); - + ExpressionAttributeValues: { ':hkey': campaignId }, + })); + + const export_data = []; + const scenelist = queryReply.Items.map(element => element.data); + + const promises = scenelist.map(scene => { + const sceneId = scene.id; + scene.tokens = {}; + scene.reveals = []; + scene.drawings = []; + + return ddb.send(new QueryCommand({ + TableName: process.env.TABLE_NAME, + KeyConditionExpression: "campaignId = :hkey and begins_with(objectId,:skey)", + ExpressionAttributeValues: { ':hkey': campaignId, ':skey': "scenes#" + sceneId }, + })).then(sceneObjects => { + sceneObjects.Items + .filter(el => el.objectId.startsWith("scenes#" + sceneId + "#tokens#")) + .forEach(el => scene.tokens[el.data.id] = el.data); + + const fogdata = sceneObjects.Items.find(el => el.objectId == "scenes#" + sceneId + "#fogdata"); + if (fogdata && fogdata.data) scene.reveals = fogdata.data; + + const drawdata = sceneObjects.Items.find(el => el.objectId == "scenes#" + sceneId + "#drawdata"); + if (drawdata && drawdata.data) scene.drawings = drawdata.data; + + export_data.push(scene); + }); }); - + + await Promise.allSettled(promises); + return { statusCode: 200, body: JSON.stringify(export_data) }; } - if(action=="getScene"){ - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - const sceneId=event.queryStringParameters?event.queryStringParameters.scene:""; + if (action == "getScene") { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; + const sceneId = event.queryStringParameters ? event.queryStringParameters.scene : ""; - return ddb.query({ - TableName: "abovevtt", + const data = await ddb.send(new QueryCommand({ + TableName: process.env.TABLE_NAME, KeyConditionExpression: "campaignId = :hkey and begins_with(objectId,:skey)", - ExpressionAttributeValues: { - ':hkey': campaignId, - ':skey': "scenes#"+sceneId - }, - }).promise().then( - (data)=>{console.log("got SceneData"); - console.log(data); - let sceneData=data.Items.find( (element)=> element.objectId=="scenes#"+sceneId+"#scenedata"); - sceneData.data.tokens=[]; - data.Items.filter( (element)=> element.objectId.startsWith("scenes#"+sceneId+"#tokens#")).forEach((element)=>sceneData.data.tokens.push(element.data)); - - - sceneData.data.reveals=[] - let fogdata=data.Items.find((element) => element.objectId=="scenes#"+sceneId+"#fogdata"); - if(fogdata && fogdata.data) - sceneData.data.reveals=fogdata.data; - sceneData.data.drawings=[] - let drawdata=data.Items.find((element) => element.objectId=="scenes#"+sceneId+"#drawdata"); - if(drawdata && drawdata.data) - sceneData.data.drawings=drawdata.data; - - - console.log("returning SceneData"); - return sceneData;} - ); + ExpressionAttributeValues: { ':hkey': campaignId, ':skey': "scenes#" + sceneId }, + })); + + console.log("got SceneData"); + const sceneData = data.Items.find(el => el.objectId == "scenes#" + sceneId + "#scenedata"); + sceneData.data.tokens = []; + data.Items + .filter(el => el.objectId.startsWith("scenes#" + sceneId + "#tokens#")) + .forEach(el => sceneData.data.tokens.push(el.data)); + + sceneData.data.reveals = []; + const fogdata = data.Items.find(el => el.objectId == "scenes#" + sceneId + "#fogdata"); + if (fogdata && fogdata.data) sceneData.data.reveals = fogdata.data; + + sceneData.data.drawings = []; + const drawdata = data.Items.find(el => el.objectId == "scenes#" + sceneId + "#drawdata"); + if (drawdata && drawdata.data) sceneData.data.drawings = drawdata.data; + + console.log("returning SceneData"); + return sceneData; } - - if(action=="getSceneList"){ - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - const queryParams ={ - TableName: "abovevtt", + if (action == "getSceneList") { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; + return ddb.send(new QueryCommand({ + TableName: process.env.TABLE_NAME, IndexName: 'sceneProperties', KeyConditionExpression: "campaignId = :hkey", - ExpressionAttributeValues: { - ':hkey': campaignId, - }, - }; - - return ddb.query(queryParams).promise().then( - (scenelist)=>{ - return scenelist; - } - ); + ExpressionAttributeValues: { ':hkey': campaignId }, + })); } - if(action=="getCurrentScene"){ - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - let getDmScene=ddb.get( - { - TableName: "abovevtt", - Key: { - campaignId: campaignId, - objectId: "dmscene", - } - } - ).promise(); - - let getPlayerScene=ddb.get( - { - TableName: "abovevtt", - Key: { - campaignId: campaignId, - objectId: "playerscene" - } - }).promise(); + if (action == "getCurrentScene") { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; - let dmSceneResult=await getDmScene; - let playerSceneResult= await getPlayerScene; - - let dmSceneId=dmSceneResult.Item? dmSceneResult.Item.data:""; - let playerSceneId=playerSceneResult.Item? playerSceneResult.Item.data:""; + const [dmSceneResult, playerSceneResult] = await Promise.all([ + ddb.send(new GetCommand({ TableName: process.env.TABLE_NAME, Key: { campaignId, objectId: "dmscene" } })), + ddb.send(new GetCommand({ TableName: process.env.TABLE_NAME, Key: { campaignId, objectId: "playerscene" } })), + ]); return { - dmscene: dmSceneId, - playerscene:playerSceneId, + dmscene: dmSceneResult.Item ? dmSceneResult.Item.data : "", + playerscene: playerSceneResult.Item ? playerSceneResult.Item.data : "", }; } + return { statusCode: 200, body: 'unknown action' }; }; diff --git a/abovevttServices/package.json b/abovevttServices/package.json index c7bd791..0a7d312 100644 --- a/abovevttServices/package.json +++ b/abovevttServices/package.json @@ -2,10 +2,11 @@ "name": "abovevttServices", "version": "1.0.0", "description": "Various HTTP Services", - "main": "src/app.js", + "main": "app.js", "author": "Daniele Martini", "license": "AGPLv3", "dependencies": { - "aws-sdk": "^2.690.0" + "@aws-sdk/client-dynamodb": "^3", + "@aws-sdk/lib-dynamodb": "^3" } } diff --git a/index.ts b/index.ts index 0bdd5ab..85ba022 100644 --- a/index.ts +++ b/index.ts @@ -78,7 +78,7 @@ class ChatAppStack extends Stack { code: new AssetCode("./abovevttServices"), architecture: Architecture.X86_64, handler: "app.handler", - runtime: Runtime.NODEJS_12_X, + runtime: Runtime.NODEJS_22_X, timeout: Duration.seconds(30), memorySize: 256, environment: { @@ -98,7 +98,7 @@ class ChatAppStack extends Stack { const connectFunc = new Function(this, "connect-lambda", { code: new AssetCode("./onconnect"), handler: "app.handler", - runtime: Runtime.NODEJS_12_X, + runtime: Runtime.NODEJS_22_X, timeout: Duration.seconds(30), memorySize: 256, environment: { @@ -110,7 +110,7 @@ class ChatAppStack extends Stack { const disconnectFunc = new Function(this, "disconnect-lambda", { code: new AssetCode("./ondisconnect"), handler: "app.handler", - runtime: Runtime.NODEJS_12_X, + runtime: Runtime.NODEJS_22_X, timeout: Duration.seconds(30), memorySize: 256, environment: { @@ -122,7 +122,7 @@ class ChatAppStack extends Stack { const keepaliveFunc = new Function(this, "keepalive-lambda", { code: new AssetCode("./keepalive"), handler: "app.handler", - runtime: Runtime.NODEJS_12_X, + runtime: Runtime.NODEJS_22_X, timeout: Duration.seconds(2), memorySize: 128, }); @@ -130,7 +130,7 @@ class ChatAppStack extends Stack { const messageFunc = new Function(this, "message-lambda", { code: new AssetCode("./sendmessage"), handler: "app.handler", - runtime: Runtime.NODEJS_12_X, + runtime: Runtime.NODEJS_22_X, timeout: Duration.seconds(30), memorySize: 256, initialPolicy: [ diff --git a/keepalive/app.js b/keepalive/app.js index fe4551e..df3b79b 100644 --- a/keepalive/app.js +++ b/keepalive/app.js @@ -1,5 +1,3 @@ -const AWS = require('aws-sdk'); - exports.handler = async event => { return { statusCode: 200, body: 'Connected.' }; }; diff --git a/keepalive/package.json b/keepalive/package.json index a33557c..9c09c1a 100644 --- a/keepalive/package.json +++ b/keepalive/package.json @@ -2,10 +2,7 @@ "name": "keepalive", "version": "1.0.0", "description": "AboveVTT Keepalive", - "main": "src/app.js", + "main": "app.js", "author": "Daniele Martini", - "license": "AGPLv3", - "dependencies": { - "aws-sdk": "^2.690.0" - } + "license": "AGPLv3" } diff --git a/onconnect/app.js b/onconnect/app.js index 8599cdc..b56b5f8 100644 --- a/onconnect/app.js +++ b/onconnect/app.js @@ -1,25 +1,18 @@ -// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 +const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); +const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb'); -const AWS = require('aws-sdk'); - -const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10', region: process.env.AWS_REGION }); +const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({ region: process.env.AWS_REGION })); exports.handler = async event => { + const campaignId = event.queryStringParameters ? event.queryStringParameters.campaign : ""; + const isDM = event.queryStringParameters && event.queryStringParameters.DM; - const campaignId=event.queryStringParameters?event.queryStringParameters.campaign:""; - - const isDM=event.queryStringParameters && event.queryStringParameters.DM; + const objectId = isDM + ? "conn#DM#" + event.requestContext.connectionId + : "conn#PLAYERS#" + event.requestContext.connectionId; + console.log("Adding " + objectId + " to " + campaignId); - let objectid=""; - if(isDM){ - objectId="conn#DM#"+event.requestContext.connectionId; - } - else{ - objectId="conn#PLAYERS#"+event.requestContext.connectionId; - } - console.log("Adding "+objectId +" to "+campaignId); const putParams = { TableName: process.env.TABLE_NAME, Item: { @@ -27,13 +20,11 @@ exports.handler = async event => { objectId: objectId, connectionId: event.requestContext.connectionId, timestamp: Date.now(), - } + }, }; try { - let result = await ddb.put(putParams).promise(); - console.log("done?"); - console.log(result); + await ddb.send(new PutCommand(putParams)); } catch (err) { return { statusCode: 500, body: 'Failed to connect: ' + JSON.stringify(err) }; } diff --git a/onconnect/package.json b/onconnect/package.json index ae52aa2..adb6d9c 100644 --- a/onconnect/package.json +++ b/onconnect/package.json @@ -2,10 +2,11 @@ "name": "on-connect", "version": "1.0.0", "description": "AboveVTT on Player Connected", - "main": "src/app.js", + "main": "app.js", "author": "Daniele Martini", "license": "AGPLv3", "dependencies": { - "aws-sdk": "^2.690.0" + "@aws-sdk/client-dynamodb": "^3", + "@aws-sdk/lib-dynamodb": "^3" } } diff --git a/ondisconnect/app.js b/ondisconnect/app.js index 6e702b8..5942114 100644 --- a/ondisconnect/app.js +++ b/ondisconnect/app.js @@ -1,39 +1,34 @@ -// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: MIT-0 - // https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-route-keys-connect-disconnect.html // The $disconnect route is executed after the connection is closed. -// The connection can be closed by the server or by the client. As the connection is already closed when it is executed, -// $disconnect is a best-effort event. +// The connection can be closed by the server or by the client. As the connection is already closed when it is executed, +// $disconnect is a best-effort event. // API Gateway will try its best to deliver the $disconnect event to your integration, but it cannot guarantee delivery. -const AWS = require('aws-sdk'); +const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); +const { DynamoDBDocumentClient, QueryCommand, DeleteCommand } = require('@aws-sdk/lib-dynamodb'); -const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10', region: process.env.AWS_REGION }); +const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({ region: process.env.AWS_REGION })); exports.handler = async event => { - console.log("trying to delete "+event.requestContext.connectionId); + console.log("trying to delete " + event.requestContext.connectionId); + const queryParams = { TableName: process.env.TABLE_NAME, IndexName: 'connectionIds', KeyConditionExpression: "connectionId = :connectionId", ExpressionAttributeValues: { - ":connectionId": event.requestContext.connectionId + ":connectionId": event.requestContext.connectionId, }, }; - let toDelete = await ddb.query(queryParams).promise(); + const toDelete = await ddb.send(new QueryCommand(queryParams)); - const deleting=toDelete.Items.map(async ({ campaignId,objectId }) => { - const deleteParams={ + const deleting = toDelete.Items.map(async ({ campaignId, objectId }) => { + console.log("Deleting campaignId: " + campaignId + " objectId: " + objectId); + return ddb.send(new DeleteCommand({ TableName: process.env.TABLE_NAME, - Key: { - campaignId: campaignId, - objectId: objectId, - } - }; - console.log("Deleting campaignId: "+campaignId+" objectId: "+objectId); - return ddb.delete(deleteParams).promise(); + Key: { campaignId, objectId }, + })); }); try { diff --git a/ondisconnect/package.json b/ondisconnect/package.json index d120e63..2c7e609 100644 --- a/ondisconnect/package.json +++ b/ondisconnect/package.json @@ -2,10 +2,11 @@ "name": "on-disconnect", "version": "1.0.0", "description": "AboveVTT", - "main": "src/app.js", + "main": "app.js", "author": "Daniele Martini", "license": "AGPLv3", "dependencies": { - "aws-sdk": "^2.690.0" + "@aws-sdk/client-dynamodb": "^3", + "@aws-sdk/lib-dynamodb": "^3" } } diff --git a/sendmessage/app.js b/sendmessage/app.js index 16c5070..50bc463 100644 --- a/sendmessage/app.js +++ b/sendmessage/app.js @@ -1,529 +1,350 @@ -// YEP.. almost all the logic is here :) +const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); +const { DynamoDBDocumentClient, QueryCommand, PutCommand, DeleteCommand, BatchWriteCommand } = require('@aws-sdk/lib-dynamodb'); +const { ApiGatewayManagementApiClient, PostToConnectionCommand, DeleteConnectionCommand } = require('@aws-sdk/client-apigatewaymanagementapi'); -const AWS = require('aws-sdk'); -const { PRIORITY_ABOVE_NORMAL } = require('constants'); - -const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10', region: process.env.AWS_REGION }); +const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({ region: process.env.AWS_REGION })); const { TABLE_NAME } = process.env; -function forwardMessage(event){ +function makeApigw(event) { + return new ApiGatewayManagementApiClient({ + endpoint: 'https://' + event.requestContext.domainName + '/' + event.requestContext.stage, + }); +} + +function forwardMessage(event) { console.log("ForwardMessage()"); - const recvMessage=JSON.parse(event.body); - const campaignId=recvMessage.campaignId; - const senderId=event.requestContext.connectionId; - let connectionData={}; + const recvMessage = JSON.parse(event.body); + const campaignId = recvMessage.campaignId; + const senderId = event.requestContext.connectionId; - return ddb.query({ - TableName: process.env.TABLE_NAME, + return ddb.send(new QueryCommand({ + TableName: TABLE_NAME, KeyConditionExpression: "campaignId = :hkey and begins_with(objectId,:skey)", - ExpressionAttributeValues: { - ':hkey': campaignId, - ':skey': "conn#" - }, - }).promise().then(function(connectionData){ - const apigwManagementApi = new AWS.ApiGatewayManagementApi({ - apiVersion: '2018-11-29', - endpoint: event.requestContext.domainName + '/' + event.requestContext.stage - }); - + ExpressionAttributeValues: { ':hkey': campaignId, ':skey': "conn#" }, + })).then(function (connectionData) { + const apigw = makeApigw(event); + let recvMessageEdit = JSON.parse(event.body); recvMessageEdit.requestTimeEpoch = String(event.requestContext.requestTimeEpoch); const eventBodySend = JSON.stringify(recvMessageEdit); - - let counter=0; - - connectionData.Items.sort( (a,b)=> b.timestamp -a.timestamp ); // sort by timestamp descending - - const MAX_CONNECTIONS=30; - let toDelete=[]; - if(connectionData.Items.length> MAX_CONNECTIONS){ + + let counter = 0; + + connectionData.Items.sort((a, b) => b.timestamp - a.timestamp); + + const MAX_CONNECTIONS = 30; + let toDelete = []; + if (connectionData.Items.length > MAX_CONNECTIONS) { console.log("DELETING OLDER CONNECTIONS EXCEEDING MAX_CONNECTIONS"); - const numToDelete=connectionData.Items.length-MAX_CONNECTIONS; - toDelete=connectionData.Items.splice(-numToDelete,numToDelete); + const numToDelete = connectionData.Items.length - MAX_CONNECTIONS; + toDelete = connectionData.Items.splice(-numToDelete, numToDelete); } // DELETE CONNECTIONS EXCEEDING MAX_CONNECTIONS SO I DON'T HAVE TO PAY 40$/hour for a single fuck-up - const deleteCalls= toDelete.map(({ objectId,connectionId,timestamp }) => { - let singleDelPromises=[]; - singleDelPromises.push(apigwManagementApi.deleteConnection({ConnectionId:connectionId}).promise()); - singleDelPromises.push(ddb.delete({ TableName: TABLE_NAME, Key: { campaignId: campaignId, objectId: objectId } }).promise()); - return Promise.allSettled(singleDelPromises); + const deleteCalls = toDelete.map(({ objectId, connectionId }) => { + return Promise.allSettled([ + apigw.send(new DeleteConnectionCommand({ ConnectionId: connectionId })), + ddb.send(new DeleteCommand({ TableName: TABLE_NAME, Key: { campaignId, objectId } })), + ]); }); + const postCalls = connectionData.Items.map(({ objectId, connectionId, timestamp }) => { + if (connectionId == senderId) return; - const postCalls = connectionData.Items.map(({ objectId,connectionId,timestamp }) => { - if(connectionId==senderId){ - return; - } - if(timestamp < Date.now()- (1000*60*120)){ - console.log(`Found expired connection, deleting ${connectionId}`) - return ddb.delete({ TableName: TABLE_NAME, Key: { campaignId: campaignId, objectId: objectId } }).promise(); + if (timestamp < Date.now() - (1000 * 60 * 120)) { + console.log(`Found expired connection, deleting ${connectionId}`); + return ddb.send(new DeleteCommand({ TableName: TABLE_NAME, Key: { campaignId, objectId } })); } - - counter++; - const postCall=apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: eventBodySend }).promise(); - return postCall.catch(function(e){ - if (e.statusCode === 410) { - console.log(`Found stale connection, deleting ${connectionId}`); - return ddb.delete({ TableName: TABLE_NAME, Key: { campaignId: campaignId, objectId: objectId } }).promise(); - } - }); + + counter++; + return apigw.send(new PostToConnectionCommand({ ConnectionId: connectionId, Data: eventBodySend })) + .catch(function (e) { + if (e.$metadata?.httpStatusCode === 410 || e.name === 'GoneException') { + console.log(`Found stale connection, deleting ${connectionId}`); + return ddb.send(new DeleteCommand({ TableName: TABLE_NAME, Key: { campaignId, objectId } })); + } + }); }); - console.log("message queued for "+counter+" connections"); + console.log("message queued for " + counter + " connections"); return Promise.allSettled(postCalls.concat(deleteCalls)); - }).catch(function(e){ + }).catch(function (e) { console.log('fuck. the query failed'); console.log(e); }); - } -// this function grabs the sceneLists, or it creates it if needed and also send the currente scene -async function sendSceneList(event){ - const recvMessage=JSON.parse(event.body); - const campaignId=recvMessage.campaignId; - const senderId=event.requestContext.connectionId; +async function sendSceneList(event) { + const recvMessage = JSON.parse(event.body); + const campaignId = recvMessage.campaignId; + const apigw = makeApigw(event); - const apigwManagementApi = new AWS.ApiGatewayManagementApi({ - apiVersion: '2018-11-29', - endpoint: event.requestContext.domainName + '/' + event.requestContext.stage - }); - - const queryParams ={ - TableName: process.env.TABLE_NAME, + const getReply = await ddb.send(new QueryCommand({ + TableName: TABLE_NAME, IndexName: 'sceneProperties', KeyConditionExpression: "campaignId = :hkey", - ExpressionAttributeValues: { - ':hkey': campaignId, - }, - }; - - let getSceneList = ddb.query(queryParams).promise(); - - return getSceneList.then(function(getReply){ - let scenelist=[]; - - let promises=[]; - let force_scene=null; + ExpressionAttributeValues: { ':hkey': campaignId }, + })); + + let scenelist = []; + const promises = []; + let force_scene = null; + + if (getReply.Items.length > 0) { + console.log("DMjoin, found some scenes. I'll send them"); + scenelist = getReply.Items.map(element => element.data); + } else { + console.log("generating empty scene"); + force_scene = 666; + const basicScene = { + id: '666', + title: "The Tavern", + dm_map: "", + player_map: "https://i.pinimg.com/originals/a2/04/d4/a204d4a2faceb7f4ae93e8bd9d146469.jpg", + scale: "100", + dm_map_usable: "0", + fog_of_war: "1", + tokens: {}, + grid: "0", + hpps: "72", + vpps: "72", + snap: "1", + fpsq: "5", + offsetx: 29, + offsety: 54, + reveals: [[0, 0, 0, 0, 2, 0]], + order: Date.now(), + }; + scenelist = [basicScene]; + + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "scenes#" + basicScene.id + "#scenedata", sceneId: basicScene.id, data: basicScene, timestamp: Date.now() }, + }))); + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "scenes#" + basicScene.id + "#fogdata", data: [[0, 0, 0, 0, 2, 0]] }, + }))); + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "dmscene", data: "666" }, + }))); + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "playerscene", data: "666" }, + }))); + } - if(getReply.Items.length>0){ - console.log("DMjoin, found some scenes. I'll send them"); - scenelist=getReply.Items.map( (element)=> element.data); - } - else{ // generate an empty scenelist - console.log("generating empty scene"); - force_scene=666; - let basicScene={ - id:'666', - title: "The Tavern", - dm_map: "", - player_map: "https://i.pinimg.com/originals/a2/04/d4/a204d4a2faceb7f4ae93e8bd9d146469.jpg", - scale: "100", - dm_map_usable: "0", - fog_of_war: "1", - tokens: {}, - grid: "0", - hpps: "72", - vpps: "72", - snap: "1", - fpsq: "5", - offsetx: 29, - offsety: 54, - reveals: [[0, 0, 0, 0, 2, 0]], - order: Date.now(), - }; - - scenelist=[basicScene]; - - promises.push( - ddb.put({ - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: "scenes#"+basicScene.id+"#scenedata", - sceneId: basicScene.id, - data:basicScene, - timestamp: Date.now(), - } - }).promise() - ); - - promises.push(ddb.put({ // also initialize fog data - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: "scenes#"+basicScene.id+"#fogdata", - data: [[0, 0, 0, 0, 2, 0]], - } - }).promise()); - - promises.push( - ddb.put({ - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: "dmscene", - data: "666", - } - }).promise() - ); - promises.push( - ddb.put({ - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: "playerscene", - data: "666", - } - }).promise() - ) - } + promises.push( + get_current_scene_id(campaignId, false, force_scene).then(sceneid => { + const sceneListMsg = { eventType: "custom/myVTT/scenelist", data: scenelist, playersSceneId: sceneid }; + return apigw.send(new PostToConnectionCommand({ ConnectionId: event.requestContext.connectionId, Data: JSON.stringify(sceneListMsg) })); + }) + ); + await Promise.allSettled(promises); - // grab the current player scene so we can tell the DM where the players are! - promises.push(get_current_scene_id(campaignId,false,force_scene).then(function(sceneid){ - // send the sceneList back to the DM - const sceneListMsg={ - eventType: "custom/myVTT/scenelist", - data: scenelist, - playersSceneId: sceneid, - } - return apigwManagementApi.postToConnection({ ConnectionId: event.requestContext.connectionId, Data: JSON.stringify(sceneListMsg) }).promise(); - })); - - - return Promise.allSettled(promises).then( - () => get_current_scene_id(campaignId,true,force_scene) - ).then( - (sceneId) => { - console.log("The Current Scene id is "+ sceneId); - console.log("sending back the message with the current scene data after a dmjoin") - const message={ - eventType: "custom/myVTT/fetchscene", - data: {sceneid:sceneId}, - }; - return apigwManagementApi.postToConnection({ ConnectionId: event.requestContext.connectionId, Data: JSON.stringify(message) }).promise(); - } - ); - }); + const sceneId = await get_current_scene_id(campaignId, true, force_scene); + console.log("The Current Scene id is " + sceneId); + const message = { eventType: "custom/myVTT/fetchscene", data: { sceneid: sceneId } }; + return apigw.send(new PostToConnectionCommand({ ConnectionId: event.requestContext.connectionId, Data: JSON.stringify(message) })); } -async function delete_scene(event){ - const recvMessage=JSON.parse(event.body); - const campaignId=recvMessage.campaignId; +async function delete_scene(event) { + const recvMessage = JSON.parse(event.body); + const campaignId = recvMessage.campaignId; + const sceneId = recvMessage.data.id; - const sceneId=recvMessage.data.id; - const apigwManagementApi = new AWS.ApiGatewayManagementApi({ - apiVersion: '2018-11-29', - endpoint: event.requestContext.domainName + '/' + event.requestContext.stage - }); console.log("deleting..."); - return ddb.query({ - TableName: process.env.TABLE_NAME, + const sceneData = await ddb.send(new QueryCommand({ + TableName: TABLE_NAME, KeyConditionExpression: "campaignId = :hkey and begins_with(objectId,:skey)", - ExpressionAttributeValues: { - ':hkey': campaignId, - ':skey': "scenes#"+sceneId - }, - ProjectionExpression: "objectId" - }).promise().then( - function (sceneData){ - console.log("got the list of objects to delete "); - console.log("I have to delete " + sceneData.Items.length + "objects"); - let promises=[]; - for(let i=0;i ({ + DeleteRequest: { Key: { campaignId, objectId } }, + })); + promises.push(ddb.send(new BatchWriteCommand({ RequestItems: { [TABLE_NAME]: batch_requests } }))); + } + return Promise.allSettled(promises); } -async function get_current_scene_id(campaignId,get_dm_scene,forced=null){ - if(forced!=null) - return forced; - let objectId=""; - if(get_dm_scene) - objectId="dmscene"; - else - objectId="playerscene"; - - return ddb.get({ - TableName: process.env.TABLE_NAME, - Key: { - campaignId: campaignId, - objectId: objectId - } - }).promise().then(function(data){ - if(data.Item){ - console.log("found the current scene"); - return data.Item.data; - } - else{ - console.log("didn't found the current scene"); - return null; - } - }); -} +async function get_current_scene_id(campaignId, get_dm_scene, forced = null) { + if (forced != null) return forced; + const objectId = get_dm_scene ? "dmscene" : "playerscene"; + const data = await ddb.send(new GetCommand({ + TableName: TABLE_NAME, + Key: { campaignId, objectId }, + })); -async function switch_scene(event){ - const recvMessage=JSON.parse(event.body); - const sceneId=recvMessage.data.sceneId; - const campaignId=recvMessage.campaignId; + if (data.Item) { + console.log("found the current scene"); + return data.Item.data; + } + console.log("didn't found the current scene"); + return null; +} - const switch_dm=recvMessage.data.switch_dm?true:false; +async function switch_scene(event) { + const recvMessage = JSON.parse(event.body); + const sceneId = recvMessage.data.sceneId; + const campaignId = recvMessage.campaignId; + const switch_dm = recvMessage.data.switch_dm ? true : false; - console.log("executing switch_scene , searchign for " + campaignId + " and scene "+sceneId); + console.log("executing switch_scene, searching for " + campaignId + " and scene " + sceneId); - return ddb.query({ // STEPE 1 get All connections based on DM / PLAYER SWITCH - TableName: process.env.TABLE_NAME, + const connectionData = await ddb.send(new QueryCommand({ + TableName: TABLE_NAME, KeyConditionExpression: "campaignId = :hkey and begins_with(objectId,:skey)", ExpressionAttributeValues: { ':hkey': campaignId, - ':skey': "conn#" + (switch_dm ? "DM#" : "PLAYERS#") + ':skey': "conn#" + (switch_dm ? "DM#" : "PLAYERS#"), }, - }).promise().then(function (connectionData) { - // STEP 2.1 CREATE THE "scene" MESSAGE AND SEND IT TO EVERYONE (including the sender if needed) - console.log("Got connectiondata"); - const apigwManagementApi = new AWS.ApiGatewayManagementApi({ - apiVersion: '2018-11-29', - endpoint: event.requestContext.domainName + '/' + event.requestContext.stage - }); + })); - const message = { - eventType: "custom/myVTT/fetchscene", - data: { - sceneid: sceneId - }, - }; + console.log("Got connectiondata"); + const apigw = makeApigw(event); + const message = { eventType: "custom/myVTT/fetchscene", data: { sceneid: sceneId } }; - const promises = connectionData.Items.map(async ({ objectId, connectionId, timestamp }) => { - const postCall = apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: JSON.stringify(message) }).promise(); - return postCall.catch(function (e) { - }); - }); + const promises = connectionData.Items.map(({ connectionId }) => + apigw.send(new PostToConnectionCommand({ ConnectionId: connectionId, Data: JSON.stringify(message) })) + .catch(function () {}) + ); - // STEP 2.2 ALSO STORE THE CURRENT SCENE ID - promises.push( - ddb.put({ - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: switch_dm ? "dmscene" : "playerscene", - data: sceneId, - } - }).promise() - ); - - return Promise.allSettled(promises); - }); + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: switch_dm ? "dmscene" : "playerscene", data: sceneId }, + }))); + + return Promise.allSettled(promises); } -async function update_scene(event){ - const recvMessage=JSON.parse(event.body); - const campaignId=recvMessage.campaignId; - let promises=[]; - const apigwManagementApi = new AWS.ApiGatewayManagementApi({ - apiVersion: '2018-11-29', - endpoint: event.requestContext.domainName + '/' + event.requestContext.stage - }); +async function update_scene(event) { + const recvMessage = JSON.parse(event.body); + const campaignId = recvMessage.campaignId; + const promises = []; - const objectId="scenes#"+recvMessage.data.id+"#scenedata"; + const objectId = "scenes#" + recvMessage.data.id + "#scenedata"; - if(recvMessage.data.isnewscene){ + if (recvMessage.data.isnewscene) { delete recvMessage.data.isnewscene; - promises.push(ddb.put({ // also initialize fog data - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: "scenes#"+recvMessage.data.id+"#fogdata", - data: [[0, 0, 0, 0, 2, 0]], - } - }).promise()); + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "scenes#" + recvMessage.data.id + "#fogdata", data: [[0, 0, 0, 0, 2, 0]] }, + }))); } - promises.push(ddb.put({ - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: objectId, - data: recvMessage.data, - sceneId: recvMessage.data.id - } - }).promise()); + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId, data: recvMessage.data, sceneId: recvMessage.data.id }, + }))); const switch_dm = recvMessage.data.id === recvMessage.sceneId; - if (switch_dm) { - console.log("forcing dm update fater update_scene"); - let fakeEventBody={ - campaignId: recvMessage.campaignId, - data: { - sceneId: recvMessage.data.id, - switch_dm: true - } - }; - let fakeEvent=Object.assign({}, event); - fakeEvent.body=JSON.stringify(fakeEventBody); + console.log("forcing dm update after update_scene"); + const fakeEvent = Object.assign({}, event, { + body: JSON.stringify({ campaignId: recvMessage.campaignId, data: { sceneId: recvMessage.data.id, switch_dm: true } }), + }); promises.push(switch_scene(fakeEvent)); } const switch_players = recvMessage.data.id === recvMessage.playersSceneId; if (switch_players) { console.log("forcing players update after update_scene"); - let fakeEventBody={ - campaignId: recvMessage.campaignId, - data: { - sceneId: recvMessage.data.id - } - }; - let fakeEvent=Object.assign({}, event); - fakeEvent.body=JSON.stringify(fakeEventBody); + const fakeEvent = Object.assign({}, event, { + body: JSON.stringify({ campaignId: recvMessage.campaignId, data: { sceneId: recvMessage.data.id } }), + }); promises.push(switch_scene(fakeEvent)); } - return Promise.allSettled(promises).then((statuses)=>{console.log("statuses from update_scene");console.log(statuses)}); + return Promise.allSettled(promises).then(statuses => { console.log("statuses from update_scene"); console.log(statuses); }); } +async function handle_player_join(event) { + const recvMessage = JSON.parse(event.body); + const campaignId = recvMessage.campaignId; + const apigw = makeApigw(event); -async function handle_player_join(event){ - const recvMessage=JSON.parse(event.body); - const campaignId=recvMessage.campaignId; - const apigwManagementApi = new AWS.ApiGatewayManagementApi({ - apiVersion: '2018-11-29', - endpoint: event.requestContext.domainName + '/' + event.requestContext.stage - }); - - return get_current_scene_id(campaignId,false).then((sceneId) => { - console.log("sending back the message with the current scene data after a playerjoin") - const message={ - eventType: "custom/myVTT/fetchscene", - data: {sceneid:sceneId}, - }; - return apigwManagementApi.postToConnection({ ConnectionId: event.requestContext.connectionId, Data: JSON.stringify(message) }).promise(); - }); + const sceneId = await get_current_scene_id(campaignId, false); + console.log("sending back the message with the current scene data after a playerjoin"); + const message = { eventType: "custom/myVTT/fetchscene", data: { sceneid: sceneId } }; + return apigw.send(new PostToConnectionCommand({ ConnectionId: event.requestContext.connectionId, Data: JSON.stringify(message) })); } // REQUEST HANDLER exports.handler = async event => { - const recvMessage=JSON.parse(event.body); - if(recvMessage.eventType=="custom/myVTT/keepalive") + const recvMessage = JSON.parse(event.body); + if (recvMessage.eventType == "custom/myVTT/keepalive") return { statusCode: 200, body: 'Data sent.' }; - - let doForwardMessage=true; - const campaignId=recvMessage.campaignId; - const isCloud=recvMessage.cloud == 1; - const promises=[]; - console.log("Campaign "+campaignId+" Event: "+recvMessage.eventType+ " requestTimeEpoch: " + event.requestContext.requestTimeEpoch); + let doForwardMessage = true; + const campaignId = recvMessage.campaignId; + const isCloud = recvMessage.cloud == 1; + const promises = []; - if(isCloud && (recvMessage.eventType=="custom/myVTT/dmjoin")){ // REPLY WITH THE SCENE LIST + console.log("Campaign " + campaignId + " Event: " + recvMessage.eventType + " requestTimeEpoch: " + event.requestContext.requestTimeEpoch); + + if (isCloud && recvMessage.eventType == "custom/myVTT/dmjoin") { promises.push(sendSceneList(event)); } - if(isCloud && (recvMessage.eventType=="custom/myVTT/playerjoin")){ // REPLY WITH THE SCENE LIST + if (isCloud && recvMessage.eventType == "custom/myVTT/playerjoin") { console.log("got a player join!"); promises.push(handle_player_join(event)); } - if(isCloud && (recvMessage.eventType=="custom/myVTT/switch_scene")){ + if (isCloud && recvMessage.eventType == "custom/myVTT/switch_scene") { promises.push(switch_scene(event)); - doForwardMessage=false; + doForwardMessage = false; } - // STORE/UPDATE TOKEN DATA IN DYNAMODB. JFF - if(isCloud && (recvMessage.eventType=="custom/myVTT/token")){ - const objectId="scenes#"+recvMessage.sceneId+"#tokens#"+recvMessage.data.id; - const putParams = { - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: objectId, - data: recvMessage.data, - timestamp: Date.now(), - } - }; - promises.push(ddb.put(putParams).promise()); + if (isCloud && recvMessage.eventType == "custom/myVTT/token") { + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "scenes#" + recvMessage.sceneId + "#tokens#" + recvMessage.data.id, data: recvMessage.data, timestamp: Date.now() }, + }))); } - // DELETE TOKEN - if(isCloud && (recvMessage.eventType=="custom/myVTT/delete_token")){ - const objectId="scenes#"+recvMessage.sceneId+"#tokens#"+recvMessage.data.id; - const delParams = { - TableName: process.env.TABLE_NAME, - Key: { - campaignId: campaignId, - objectId: objectId, - } - }; - promises.push(ddb.delete(delParams).promise()); + if (isCloud && recvMessage.eventType == "custom/myVTT/delete_token") { + promises.push(ddb.send(new DeleteCommand({ + TableName: TABLE_NAME, + Key: { campaignId, objectId: "scenes#" + recvMessage.sceneId + "#tokens#" + recvMessage.data.id }, + }))); } - if(isCloud && (recvMessage.eventType=="custom/myVTT/delete_scene")){ + if (isCloud && recvMessage.eventType == "custom/myVTT/delete_scene") { promises.push(delete_scene(event)); } - // STORE FOG - if(isCloud && (recvMessage.eventType=="custom/myVTT/fogdata")){ - const objectId="scenes#"+recvMessage.sceneId+"#fogdata"; - const putParams = { - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: objectId, - data: recvMessage.data, - timestamp: Date.now(), - } - }; - promises.push(ddb.put(putParams).promise()); + if (isCloud && recvMessage.eventType == "custom/myVTT/fogdata") { + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "scenes#" + recvMessage.sceneId + "#fogdata", data: recvMessage.data, timestamp: Date.now() }, + }))); } - // STORE DRAWINGS - if(isCloud && (recvMessage.eventType=="custom/myVTT/drawdata")){ - const objectId="scenes#"+recvMessage.sceneId+"#drawdata"; - const putParams = { - TableName: process.env.TABLE_NAME, - Item: { - campaignId: campaignId, - objectId: objectId, - data: recvMessage.data, - timestamp: Date.now(), - } - }; - promises.push(ddb.put(putParams).promise()); + if (isCloud && recvMessage.eventType == "custom/myVTT/drawdata") { + promises.push(ddb.send(new PutCommand({ + TableName: TABLE_NAME, + Item: { campaignId, objectId: "scenes#" + recvMessage.sceneId + "#drawdata", data: recvMessage.data, timestamp: Date.now() }, + }))); } -// - if(isCloud && (recvMessage.eventType=="custom/myVTT/update_scene")){ // THIS WILL CREATE OR UPDATE A SCENE (AND OPTIONALLY FORCE A SYNC FOR THE PLAYERS) + + if (isCloud && recvMessage.eventType == "custom/myVTT/update_scene") { promises.push(update_scene(event)); - doForwardMessage=false; + doForwardMessage = false; } - if(doForwardMessage) - promises.push(forwardMessage(event)); // FORWARD THE MESSAGE TO ALL THE OTHER USERS - + if (doForwardMessage) + promises.push(forwardMessage(event)); try { await Promise.allSettled(promises); @@ -533,6 +354,5 @@ exports.handler = async event => { return { statusCode: 500, body: 'Failed to connect: ' + JSON.stringify(err) }; } console.log("finished"); - return { statusCode: 200, body: 'Data sent.' }; -} - + return { statusCode: 200, body: 'Data sent.' }; +}; diff --git a/sendmessage/package.json b/sendmessage/package.json index 09e57fa..b7d2ce8 100644 --- a/sendmessage/package.json +++ b/sendmessage/package.json @@ -2,10 +2,12 @@ "name": "send-message", "version": "1.0.0", "description": "sendmessage example for WebSockets on API Gateway", - "main": "src/app.js", + "main": "app.js", "author": "Daniele Martini", "license": "AGPLv3", "dependencies": { - "aws-sdk": "^2.690.0" + "@aws-sdk/client-dynamodb": "^3", + "@aws-sdk/lib-dynamodb": "^3", + "@aws-sdk/client-apigatewaymanagementapi": "^3" } }