load archived game if not found

This commit is contained in:
Evan
2025-02-17 19:30:30 -08:00
parent 836e7db5dc
commit 6a66d0c52d
5 changed files with 91 additions and 52 deletions
+46
View File
@@ -128,6 +128,52 @@ async function archiveToGCS(gameRecord: GameRecord) {
console.log(`${gameRecord.id}: game record successfully written to GCS`);
}
export async function readGameRecord(gameId: GameID): Promise<GameRecord> {
try {
const file = bucket.file(gameId);
// Check if file exists
const [exists] = await file.exists();
if (!exists) {
throw new Error(`Game record ${gameId} not found in GCS`);
}
// Download and parse file content
const [content] = await file.download();
const gameRecord = JSON.parse(content.toString());
// Validate the parsed content against the schema
const validatedRecord = GameRecordSchema.parse(gameRecord);
console.log(`${gameId}: Successfully read game record from GCS`);
return validatedRecord;
} catch (error) {
console.error(`${gameId}: Error reading game record from GCS: ${error}`, {
message: error?.message || error,
stack: error?.stack,
name: error?.name,
...(error && typeof error === "object" ? error : {}),
});
throw error;
}
}
export async function gameRecordExists(gameId: GameID): Promise<boolean> {
try {
const file = bucket.file(gameId);
const [exists] = await file.exists();
return exists;
} catch (error) {
console.error(`${gameId}: Error checking archive existence: ${error}`, {
message: error?.message || error,
stack: error?.stack,
name: error?.name,
...(error && typeof error === "object" ? error : {}),
});
return false;
}
}
function anonymizeIPv4(ipv4: string): string | null {
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
+5 -5
View File
@@ -24,13 +24,13 @@ export class GameManager {
return this.games.filter((g) => g.phase() == phase);
}
addClient(client: Client, gameID: GameID, lastTurn: number) {
addClient(client: Client, gameID: GameID, lastTurn: number): boolean {
const game = this.games.find((g) => g.id == gameID);
if (!game) {
console.log(`game id ${gameID} not found`);
return;
if (game) {
game.addClient(client, lastTurn);
return true;
}
game.addClient(client, lastTurn);
return false;
}
updateGameConfig(gameID: GameID, gameConfig: GameConfig) {
+23 -8
View File
@@ -10,6 +10,7 @@ import {
GameRecord,
GameRecordSchema,
LogSeverity,
ServerStartGameMessageSchema,
} from "../core/Schemas";
import {
GameEnv,
@@ -19,7 +20,7 @@ import {
import { slog } from "./StructuredLog";
import { Client } from "./Client";
import { GamePhase, GameServer } from "./GameServer";
import { archive } from "./Archive";
import { archive, gameRecordExists, readGameRecord } from "./Archive";
import { DiscordBot } from "./DiscordBot";
import {
sanitizeUsername,
@@ -176,13 +177,14 @@ app.put("/private_lobby/:id", (req, res) => {
});
});
app.get("/lobby/:id/exists", (req, res) => {
app.get("/lobby/:id/exists", async (req, res) => {
const lobbyId = req.params.id;
console.log(`checking lobby ${lobbyId} exists`);
const lobbyExists = gm.hasActiveGame(lobbyId);
let gameExists = gm.hasActiveGame(lobbyId);
if (!gameExists) {
gameExists = await gameRecordExists(lobbyId);
}
res.json({
exists: lobbyExists,
exists: gameExists,
});
});
@@ -212,7 +214,7 @@ app.get("*", function (req, res) {
});
wss.on("connection", (ws, req) => {
ws.on("message", (message: string) => {
ws.on("message", async (message: string) => {
try {
const clientMsg: ClientMessage = ClientMessageSchema.parse(
JSON.parse(message),
@@ -233,7 +235,7 @@ wss.on("connection", (ws, req) => {
return;
}
clientMsg.username = sanitizeUsername(clientMsg.username);
gm.addClient(
const wasFound = gm.addClient(
new Client(
clientMsg.clientID,
clientMsg.persistentID,
@@ -244,6 +246,19 @@ wss.on("connection", (ws, req) => {
clientMsg.gameID,
clientMsg.lastTurn,
);
if (!wasFound) {
console.log(`game ${clientMsg.gameID} not found, loading from gcs`);
const record = await readGameRecord(clientMsg.gameID);
ws.send(
JSON.stringify(
ServerStartGameMessageSchema.parse({
type: "start",
turns: record.turns,
config: record.gameConfig,
}),
),
);
}
}
if (clientMsg.type == "log") {
slog({