From 16536f6f4f146c938e494c1ddaaee8aa6767b04e Mon Sep 17 00:00:00 2001 From: Taukon <83957880+Taukon@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:37:19 +0900 Subject: [PATCH] feat: add sample scripts to initialize S3 and DynamoDB --- infra-samples/README.md | 4 + infra-samples/aws/README.md | 17 +++ infra-samples/aws/create-dynamodb-table.js | 164 +++++++++++++++++++++ infra-samples/aws/create-s3-bucket.js | 36 +++++ 4 files changed, 221 insertions(+) create mode 100644 infra-samples/README.md create mode 100644 infra-samples/aws/README.md create mode 100644 infra-samples/aws/create-dynamodb-table.js create mode 100644 infra-samples/aws/create-s3-bucket.js diff --git a/infra-samples/README.md b/infra-samples/README.md new file mode 100644 index 0000000..b995664 --- /dev/null +++ b/infra-samples/README.md @@ -0,0 +1,4 @@ +# Infrastructure Samples + +This directory contains sample scripts for initializing external infrastructure resources such as cloud services and databases. +It is intended to help developers quickly set up necessary components for local development, testing, or demonstration purposes. diff --git a/infra-samples/aws/README.md b/infra-samples/aws/README.md new file mode 100644 index 0000000..ce2bd6b --- /dev/null +++ b/infra-samples/aws/README.md @@ -0,0 +1,17 @@ +# Samples for AWS + +## S3 +WebRTC statistics are stored as ZIP files on S3. + +### Run +``` +$ node ./infra-samples/aws/create-s3-bucket.js +``` + +## DynamoDB +DynamoDB manages meeting metadata. You can see the schema in [API.md](../../API.md#identity-request) + +### Run +``` +$ node ./infra-samples/aws/create-dynamodb-table.js +``` \ No newline at end of file diff --git a/infra-samples/aws/create-dynamodb-table.js b/infra-samples/aws/create-dynamodb-table.js new file mode 100644 index 0000000..8c1c1f1 --- /dev/null +++ b/infra-samples/aws/create-dynamodb-table.js @@ -0,0 +1,164 @@ +const AWS = require('aws-sdk'); + +const { + RTCSTATS_METADATA_TABLE, + AWS_REGION: region, + RTCSTATS_DYNAMODB_ENDPOINT: endpoint +} = process.env; + +const config = endpoint ? { endpoint, + region } : { region }; + +AWS.config.update(config); + +const tableConfig = { + TableName: RTCSTATS_METADATA_TABLE, + AttributeDefinitions: [ + { + AttributeName: 'conferenceId', + AttributeType: 'S' + }, + { + AttributeName: 'conferenceUrl', + AttributeType: 'S' + }, + { + AttributeName: 'dumpId', + AttributeType: 'S' + }, + { + AttributeName: 'startDate', + AttributeType: 'N' + }, + { + AttributeName: 'sessionId', + AttributeType: 'S' + } + ], + KeySchema: [ + { + AttributeName: 'conferenceId', + KeyType: 'HASH' + }, + { + AttributeName: 'dumpId', + KeyType: 'RANGE' + } + ], + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5 + }, + GlobalSecondaryIndexes: [ + { + IndexName: 'conferenceUrl-startDate-index', + KeySchema: [ + { + AttributeName: 'conferenceUrl', + KeyType: 'HASH' + }, + { + AttributeName: 'startDate', + KeyType: 'RANGE' + } + ], + Projection: { + ProjectionType: 'ALL' + }, + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5 + } + }, + { + IndexName: 'conferenceId-startDate-index', + KeySchema: [ + { + AttributeName: 'conferenceId', + KeyType: 'HASH' + }, + { + AttributeName: 'startDate', + KeyType: 'RANGE' + } + ], + Projection: { + ProjectionType: 'ALL' + }, + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5 + } + }, + { + IndexName: 'sessionId-startDate-index', + KeySchema: [ + { + AttributeName: 'sessionId', + KeyType: 'HASH' + }, + { + AttributeName: 'startDate', + KeyType: 'RANGE' + } + ], + Projection: { + ProjectionType: 'ALL' + }, + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5 + } + } + ], + StreamSpecification: { + StreamEnabled: false + } +}; + +const ddb = new AWS.DynamoDB(); + + +const createTable = () => ddb.createTable(tableConfig, err => { + if (err) { + console.log('Could not create table', err); + } +}); + +const deleteTable = () => new Promise((resolve, reject) => { + ddb.deleteTable({ + TableName: RTCSTATS_METADATA_TABLE + }, (err, data) => { + if (err) { + reject(err); + } else { + console.log(data); + resolve(data); + } + }); +}); + +ddb.listTables(async (err, data) => { + if (err) { + console.error('Could not list tables', err); + + return; + } + + const tableExists = Boolean(data.TableNames.find(t => t === RTCSTATS_METADATA_TABLE)); + + if (tableExists) { + try { + console.log('Table exists, deleting and recreating...'); + + await deleteTable(); + createTable(); + // eslint-disable-next-line no-catch-shadow, no-shadow + } catch (err) { + console.error('Could not delete table', err); + } + } else { + console.log('Creating new table...'); + createTable(); + } +}); diff --git a/infra-samples/aws/create-s3-bucket.js b/infra-samples/aws/create-s3-bucket.js new file mode 100644 index 0000000..7a24ffc --- /dev/null +++ b/infra-samples/aws/create-s3-bucket.js @@ -0,0 +1,36 @@ +const AWS = require('aws-sdk'); + +const { + RTCSTATS_S3_BUCKET, + AWS_REGION: region, + RTCSTATS_S3_ENDPOINT: endpoint +} = process.env; + +const config = { region }; + +AWS.config.update(config); + +const s3Config = endpoint ? { endpoint } : {}; + +const bucketConfig = { + Bucket: RTCSTATS_S3_BUCKET +}; + +const s3 = new AWS.S3(s3Config); + + +// --- Workaround for LocalStack S3 endpoint issue --- +// The AWS SDK v2 may not handle the endpoint URL correctly, leading to an `InvalidLocationConstraint` error. +// To fix this, we explicitly set only the hostname to an internal property of the SDK. +// See: https://github.com/localstack/localstack/issues/8000 +if (endpoint) { + const url = new URL(endpoint); + + s3.api.globalEndpoint = url.hostname; +} + +s3.createBucket(bucketConfig, err => { + if (err) { + console.error('Could not create bucket:', err); + } +});