Skip to content

Commit

Permalink
feat: commit mutations to DB and S3 when concatenating
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeg committed Jan 26, 2025
1 parent 75881ff commit 96445f0
Showing 1 changed file with 64 additions and 37 deletions.
101 changes: 64 additions & 37 deletions scripts/concat_games.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// to run this use the command below from ntc root
// npm run concat gameid1 gameid2 gameid3 [...]

import BinaryFrame from '../public/js/BinaryFrame.js';
import { peek } from '../public/views/utils.js';
import { Upload } from '@aws-sdk/lib-storage';
import { S3Client, DeleteObjectsCommand } from '@aws-sdk/client-s3';
import zlib from 'zlib';
import BaseGame from '../public/views/BaseGame.js';
import dbPool from '../modules/db.js';

export async function getGameFrames(gameid) {
const game_url = `https://nestrischamps.io/api/games/${gameid}`;
Expand Down Expand Up @@ -56,7 +60,21 @@ export async function getGameFrames(gameid) {
(async function () {
const s3Client = new S3Client({ region: process.env.GAME_FRAMES_REGION });
const gameids = process.argv.slice(2);

if (gameids.length < 2) {
throw new Error(`Supply at least 2 gameids`);
}

const invalidGameIds = gameids.filter(
gameid => !/^[1-9][0-9]*$/.test(gameid)
);

if (invalidGameIds.length) {
throw new Error(`Invalid game ids supplied: [${invalidGameIds.join(',')}]`);
}

const games = await Promise.all(gameids.map(gameid => getGameFrames(gameid)));

const file_keys = games.map(game =>
game.gamedata.frame_url.replace(/^https:\/\/[^/]+\//, '')
);
Expand All @@ -82,12 +100,13 @@ export async function getGameFrames(gameid) {
});

const game = new BaseGame({});
const firstClientGameId = peek(games[0].frames).gameid;

games
.map(game => game.frames)
.flat()
.forEach(frame => {
frame.gameid = 1;
frame.gameid = firstClientGameId;
frame_stream.write(BinaryFrame.encode(frame));
game.setFrame(frame);
});
Expand All @@ -104,49 +123,57 @@ export async function getGameFrames(gameid) {
const lastPoints = peek(game.points);
const lastClear = peek(game.clears);

// gross sql creation via string interpolation, but it's meant to be run by hand on console 🤷
// operator should check!
const sqls = [
// warning below actions are destructive
// note: we use sql concatenation because we know the data types are sql safe - don't do that other

// update last game of sequence
console.log('DB: updating last game');

let res = await dbPool.query(
`
update scores
set
start_level=${game.frames[2].raw.level}
, tetris_rate=${lastClear.tetris_rate}
, num_droughts=${lastPieces.i_droughts.count}
, max_drought=${lastPieces.i_droughts.max}
, das_avg=${lastPieces.das.avg}
, duration=${game.duration}
, clears='${game.clears.map(clear => clear.cleared).join('')}'
, pieces='${game.pieces.map(piece => piece.piece).join('')}'
, transition=${lastPoints.score.transition}
, num_frames=${game.frames.length}
, frame_file='${frame_file}'
where
id=${lastGameId}
;
`,
...gameids
.slice(0, -1)
.map(gameid => `delete from scores where id=${gameid};`),
];

console.log('SQL commands to tun to update DB:');
console.log(sqls.join('\n'));
console.log('==========:');

// WARNING: Below is destructive!! It drops the objects from S3, there's no turning back!

const input = {
// DeleteObjectsRequest
UPDATE scores
start_level=${game.frames[2].raw.level},
tetris_rate=${lastClear.tetris_rate},
num_droughts=${lastPieces.i_droughts.count},
max_drought=${lastPieces.i_droughts.max},
das_avg=${lastPieces.das.avg},
duration=${game.duration},
clears='${game.clears.map(clear => clear.cleared).join('')}',
pieces='${game.pieces.map(piece => piece.piece).join('')}',
transition=${lastPoints.score.transition},
num_frames=${game.frames.length},
frame_file='${frame_file}'
WHERE
id=${lastGameId}
`
);

if (res.rowCount !== 1) {
throw new Error(
`Unexpected number of rows updated: ${res.rowCount} for game id: ${lastGameId}`
);
}

// delete games that were collapsed into one
console.log('DB: deleting collapsed games (i.e. all but last)');

const gamesToDelete = gameids.slice(0, -1);

for (const gameid of gamesToDelete) {
await dbPool.query(`DELETE from scoresWHERE id=${gameid}`);
}

// And remove the old frame files
console.log(`Deleting old frame files in S3: \n${file_keys.join('\n')}`);

const deleteCmdInput = {
Bucket: process.env.GAME_FRAMES_BUCKET,
Delete: {
// Delete
Objects: file_keys.map(key => ({ Key: key })),
Quiet: false,
},
};
const command = new DeleteObjectsCommand(input);
const command = new DeleteObjectsCommand(deleteCmdInput);

console.log(`Deleting old files: \n${file_keys.join('\n')}`);
await s3Client.send(command);
})();

0 comments on commit 96445f0

Please sign in to comment.