From d2dd2622205d0729d79d9175ca1c6d2343da62e8 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 5 Mar 2025 16:48:52 -0800 Subject: [PATCH] update map=>mapType map is keyword --- src/server/Archive.ts | 101 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/src/server/Archive.ts b/src/server/Archive.ts index 8227de6ee..01094599f 100644 --- a/src/server/Archive.ts +++ b/src/server/Archive.ts @@ -1,27 +1,29 @@ import { GameRecord, GameID } from "../core/Schemas"; import { S3 } from "@aws-sdk/client-s3"; import { RedshiftData } from "@aws-sdk/client-redshift-data"; +import { + GameEnv, + getServerConfigFromServer, +} from "../core/configuration/Config"; + +const config = getServerConfigFromServer(); const s3 = new S3({ region: "eu-west-1" }); -const bucket = "openfront-games"; -const redshiftData = new RedshiftData({ region: "eu-west-1" }); - -// Redshift Serverless configuration -const REDSHIFT_WORKGROUP = "game-analytics"; -const REDSHIFT_DATABASE = "game_archive"; +const gameBucket = "openfront-games"; +const analyticsBucket = "openfront-analytics"; export async function archive(gameRecord: GameRecord) { try { // Archive to Redshift Serverless - await archiveToRedshift(gameRecord); + await archiveAnalyticsToS3(gameRecord); // Archive to S3 if there are turns if (gameRecord.turns.length > 0) { console.log( - `${gameRecord.id}: game has more than zero turns, attempting to write to S3`, + `${gameRecord.id}: game has more than zero turns, attempting to write to full game to S3`, ); - await archiveToS3(gameRecord); + await archiveFullGameToS3(gameRecord); } } catch (error) { console.error(`${gameRecord.id}: Final archive error: ${error}`, { @@ -33,55 +35,54 @@ export async function archive(gameRecord: GameRecord) { } } -async function archiveToRedshift(gameRecord: GameRecord) { - const row = { +async function archiveAnalyticsToS3(gameRecord: GameRecord) { + // Create analytics data object (similar to what was going to Redshift) + const analyticsData = { id: gameRecord.id, - start_time: new Date(gameRecord.startTimestampMS), - end_time: new Date(gameRecord.endTimestampMS), + env: config.env(), + start_time: new Date(gameRecord.startTimestampMS).toISOString(), + end_time: new Date(gameRecord.endTimestampMS).toISOString(), duration_seconds: gameRecord.durationSeconds, number_turns: gameRecord.num_turns, game_mode: gameRecord.gameConfig.gameType, winner: gameRecord.winner, difficulty: gameRecord.gameConfig.difficulty, - map: gameRecord.gameConfig.gameMap, - players: JSON.stringify( - gameRecord.players.map((p) => ({ - username: p.username, - ip: p.ip, - persistentID: p.persistentID, - clientID: p.clientID, - })), - ), + mapType: gameRecord.gameConfig.gameMap, + players: gameRecord.players.map((p) => ({ + username: p.username, + ip: p.ip, + persistentID: p.persistentID, + clientID: p.clientID, + })), }; - // Convert the row to SQL parameters for insertion - const params = { - Sql: ` - INSERT INTO game_results ( - id, start_time, end_time, duration_seconds, number_turns, game_mode, - winner, difficulty, map, players - ) VALUES ( - '${row.id}', - '${row.start_time.toISOString()}', - '${row.end_time.toISOString()}', - ${row.duration_seconds}, - ${row.number_turns}, - '${row.game_mode}', - '${row.winner}', - '${row.difficulty}', - '${row.map}', - JSON_PARSE('${row.players}') - ) - `, - WorkgroupName: REDSHIFT_WORKGROUP, - Database: REDSHIFT_DATABASE, - }; + try { + // Store analytics data using just the game ID as the key + const analyticsKey = `${gameRecord.id}.json`; - await redshiftData.executeStatement(params); - console.log(`${gameRecord.id}: wrote game metadata to Redshift`); + await s3.putObject({ + Bucket: analyticsBucket, + Key: analyticsKey, + Body: JSON.stringify(analyticsData), + ContentType: "application/json", + }); + + console.log(`${gameRecord.id}: successfully wrote game analytics to S3`); + } catch (error) { + console.error( + `${gameRecord.id}: Error writing game analytics to S3: ${error}`, + { + message: error?.message || error, + stack: error?.stack, + name: error?.name, + ...(error && typeof error === "object" ? error : {}), + }, + ); + throw error; + } } -async function archiveToS3(gameRecord: GameRecord) { +async function archiveFullGameToS3(gameRecord: GameRecord) { // Create a deep copy to avoid modifying the original const recordCopy = JSON.parse(JSON.stringify(gameRecord)); @@ -93,7 +94,7 @@ async function archiveToS3(gameRecord: GameRecord) { try { await s3.putObject({ - Bucket: bucket, + Bucket: gameBucket, Key: recordCopy.id, Body: JSON.stringify(recordCopy), ContentType: "application/json", @@ -110,7 +111,7 @@ export async function readGameRecord(gameId: GameID): Promise { try { // Check if file exists and download in one operation const response = await s3.getObject({ - Bucket: bucket, + Bucket: gameBucket, Key: gameId, }); @@ -133,7 +134,7 @@ export async function readGameRecord(gameId: GameID): Promise { export async function gameRecordExists(gameId: GameID): Promise { try { await s3.headObject({ - Bucket: bucket, + Bucket: gameBucket, Key: gameId, }); return true;