Add Prettier and ESLint tooling (Refs #77)
This commit is contained in:
@@ -5,58 +5,119 @@ import { recordLeaderboardTelemetry } from './leaderboard-ingest.js';
|
||||
import { latestGameSubmission } from './status-evidence.js';
|
||||
|
||||
export function listTelemetry(): GameTelemetry[] {
|
||||
const rows = db().prepare(`SELECT t.payload FROM server_telemetry t JOIN servers s ON s.name = t.server
|
||||
WHERE s.destroyed_at IS NULL AND t.payload IS NOT NULL`).all() as Array<{ payload: string }>;
|
||||
return rows.map(row => JSON.parse(row.payload) as GameTelemetry);
|
||||
const rows = db()
|
||||
.prepare(
|
||||
`SELECT t.payload FROM server_telemetry t JOIN servers s ON s.name = t.server
|
||||
WHERE s.destroyed_at IS NULL AND t.payload IS NOT NULL`
|
||||
)
|
||||
.all() as Array<{ payload: string }>;
|
||||
return rows.map((row) => JSON.parse(row.payload) as GameTelemetry);
|
||||
}
|
||||
|
||||
export function saveTelemetry(report: GameTelemetry): GameTelemetry {
|
||||
// Keep callers outside the HTTP route atomic too.
|
||||
const handle = db();
|
||||
return handle.transaction(() => {
|
||||
const row = handle.prepare('SELECT payload FROM server_telemetry WHERE server = ?').get(report.server) as { payload: string | null } | undefined;
|
||||
const previous: GameTelemetry | undefined = row?.payload ? JSON.parse(row.payload) : undefined;
|
||||
const row = handle
|
||||
.prepare('SELECT payload FROM server_telemetry WHERE server = ?')
|
||||
.get(report.server) as { payload: string | null } | undefined;
|
||||
const previous: GameTelemetry | undefined = row?.payload
|
||||
? JSON.parse(row.payload)
|
||||
: undefined;
|
||||
recordLeaderboardTelemetry(handle, report);
|
||||
// Record each occupancy transition at receipt, before a heartbeat can
|
||||
// replace game_start or an empty report between status polls.
|
||||
const after = latestGameSubmission(report.server);
|
||||
if (!after || Date.parse(report.receivedAt) > Date.parse(after)) {
|
||||
if (report.players.length > 0) {
|
||||
handle.prepare('UPDATE servers SET active_since = COALESCE(active_since, ?), inactive_since = NULL WHERE name = ?')
|
||||
handle
|
||||
.prepare(
|
||||
'UPDATE servers SET active_since = COALESCE(active_since, ?), inactive_since = NULL WHERE name = ?'
|
||||
)
|
||||
.run(report.receivedAt, report.server);
|
||||
if (report.event === 'game_start') {
|
||||
handle.prepare('UPDATE servers SET game_started_at = ?, game_ended_at = NULL WHERE name = ?').run(report.receivedAt, report.server);
|
||||
handle
|
||||
.prepare(
|
||||
'UPDATE servers SET game_started_at = ?, game_ended_at = NULL WHERE name = ?'
|
||||
)
|
||||
.run(report.receivedAt, report.server);
|
||||
} else if (report.event === 'game_end') {
|
||||
handle.prepare('UPDATE servers SET game_ended_at = ? WHERE name = ?').run(report.receivedAt, report.server);
|
||||
handle
|
||||
.prepare('UPDATE servers SET game_ended_at = ? WHERE name = ?')
|
||||
.run(report.receivedAt, report.server);
|
||||
}
|
||||
} else {
|
||||
handle.prepare(`UPDATE servers SET active_since = NULL, inactive_since = COALESCE(inactive_since, ?),
|
||||
game_started_at = NULL, game_ended_at = NULL WHERE name = ?`).run(report.receivedAt, report.server);
|
||||
handle
|
||||
.prepare(
|
||||
`UPDATE servers SET active_since = NULL, inactive_since = COALESCE(inactive_since, ?),
|
||||
game_started_at = NULL, game_ended_at = NULL WHERE name = ?`
|
||||
)
|
||||
.run(report.receivedAt, report.server);
|
||||
}
|
||||
}
|
||||
const serverTiming = handle.prepare(`SELECT active_since AS activeSince, inactive_since AS inactiveSince,
|
||||
game_started_at AS gameStartedAt, game_ended_at AS gameEndedAt FROM servers WHERE name = ?`).get(report.server) as ServerTiming;
|
||||
const match = handle.prepare('SELECT id FROM leaderboard_matches WHERE server = ? ORDER BY id DESC LIMIT 1').get(report.server) as { id: number };
|
||||
const serverTiming = handle
|
||||
.prepare(
|
||||
`SELECT active_since AS activeSince, inactive_since AS inactiveSince,
|
||||
game_started_at AS gameStartedAt, game_ended_at AS gameEndedAt FROM servers WHERE name = ?`
|
||||
)
|
||||
.get(report.server) as ServerTiming;
|
||||
const match = handle
|
||||
.prepare('SELECT id FROM leaderboard_matches WHERE server = ? ORDER BY id DESC LIMIT 1')
|
||||
.get(report.server) as { id: number };
|
||||
const sameMatch = previous?.timing?.matchId === match.id;
|
||||
// A gap beyond the normal heartbeat window cannot establish continuity.
|
||||
const continuous = previous && Date.parse(report.receivedAt) - Date.parse(previous.receivedAt) <= 120_000;
|
||||
report = { ...report, timing: { matchId: match.id, server: serverTiming, players: Object.fromEntries(report.players.map(player => {
|
||||
const prior = continuous ? previous?.timing?.players[player.guid] : undefined;
|
||||
return [player.guid, {
|
||||
serverJoinedAt: prior?.serverJoinedAt ?? report.receivedAt,
|
||||
matchJoinedAt: sameMatch && prior ? prior.matchJoinedAt : report.receivedAt,
|
||||
roundStarted: sameMatch && prior ? prior.roundStarted : report.event === 'game_start' ? 1 : report.round
|
||||
}];
|
||||
})) } };
|
||||
handle.prepare(`INSERT INTO server_telemetry (server, round, players, received_at, payload)
|
||||
const continuous =
|
||||
previous && Date.parse(report.receivedAt) - Date.parse(previous.receivedAt) <= 120_000;
|
||||
report = {
|
||||
...report,
|
||||
timing: {
|
||||
matchId: match.id,
|
||||
server: serverTiming,
|
||||
players: Object.fromEntries(
|
||||
report.players.map((player) => {
|
||||
const prior = continuous
|
||||
? previous?.timing?.players[player.guid]
|
||||
: undefined;
|
||||
return [
|
||||
player.guid,
|
||||
{
|
||||
serverJoinedAt: prior?.serverJoinedAt ?? report.receivedAt,
|
||||
matchJoinedAt:
|
||||
sameMatch && prior ? prior.matchJoinedAt : report.receivedAt,
|
||||
roundStarted:
|
||||
sameMatch && prior
|
||||
? prior.roundStarted
|
||||
: report.event === 'game_start'
|
||||
? 1
|
||||
: report.round
|
||||
}
|
||||
];
|
||||
})
|
||||
)
|
||||
}
|
||||
};
|
||||
handle
|
||||
.prepare(
|
||||
`INSERT INTO server_telemetry (server, round, players, received_at, payload)
|
||||
VALUES (?, ?, ?, ?, ?) ON CONFLICT(server) DO UPDATE SET
|
||||
round = excluded.round, players = excluded.players, received_at = excluded.received_at, payload = excluded.payload`)
|
||||
.run(report.server, report.event === 'game_start' ? 0 : report.round, report.players.length, report.receivedAt, JSON.stringify(report));
|
||||
round = excluded.round, players = excluded.players, received_at = excluded.received_at, payload = excluded.payload`
|
||||
)
|
||||
.run(
|
||||
report.server,
|
||||
report.event === 'game_start' ? 0 : report.round,
|
||||
report.players.length,
|
||||
report.receivedAt,
|
||||
JSON.stringify(report)
|
||||
);
|
||||
if (report.event === 'game_end') {
|
||||
// Legacy betas also take match completion directly from the script.
|
||||
if (report.round >= MIN_RECORDED_ROUND) handle.prepare(`UPDATE beta_servers SET match_seen_at = ? WHERE server = ? AND server_deleted_at IS NULL AND stage = 'awaiting-match'
|
||||
AND healthy_at <= ? AND beta_id IN (SELECT id FROM betas WHERE state = 'running')`)
|
||||
.run(report.receivedAt, report.server, report.receivedAt);
|
||||
if (report.round >= MIN_RECORDED_ROUND)
|
||||
handle
|
||||
.prepare(
|
||||
`UPDATE beta_servers SET match_seen_at = ? WHERE server = ? AND server_deleted_at IS NULL AND stage = 'awaiting-match'
|
||||
AND healthy_at <= ? AND beta_id IN (SELECT id FROM betas WHERE state = 'running')`
|
||||
)
|
||||
.run(report.receivedAt, report.server, report.receivedAt);
|
||||
}
|
||||
return report;
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user