feat: add startMonitor, stopMonitor, cleanupAllShards module exports
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
const WebSocket = require('ws');
|
||||
|
||||
const db = require('../database');
|
||||
const { getWebSocketManager } = require('./websocket-manager');
|
||||
const { getRoomInfo } = require('./jackbox-api');
|
||||
|
||||
class EcastShardClient {
|
||||
@@ -420,4 +422,149 @@ class EcastShardClient {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { EcastShardClient };
|
||||
const activeShards = new Map();
|
||||
|
||||
function broadcastAndPersist(sessionId, gameId) {
|
||||
return (eventType, eventData) => {
|
||||
const wsManager = getWebSocketManager();
|
||||
if (wsManager) {
|
||||
wsManager.broadcastEvent(eventType, eventData, parseInt(sessionId, 10));
|
||||
}
|
||||
|
||||
if (['room.connected', 'lobby.player-joined', 'game.started', 'game.ended'].includes(eventType)) {
|
||||
const status = eventType === 'game.ended' ? 'completed' : 'monitoring';
|
||||
try {
|
||||
db.prepare(
|
||||
'UPDATE session_games SET player_count = ?, player_count_check_status = ? WHERE session_id = ? AND id = ?'
|
||||
).run(eventData.playerCount ?? null, status, sessionId, gameId);
|
||||
} catch (e) {
|
||||
console.error('[Shard Monitor] DB update failed:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventType === 'room.disconnected') {
|
||||
const reason = eventData.reason;
|
||||
const status =
|
||||
reason === 'room_closed' ? 'completed' : reason === 'manually_stopped' ? 'stopped' : 'failed';
|
||||
try {
|
||||
const game = db
|
||||
.prepare('SELECT player_count_check_status FROM session_games WHERE session_id = ? AND id = ?')
|
||||
.get(sessionId, gameId);
|
||||
if (game && game.player_count_check_status !== 'completed') {
|
||||
db.prepare('UPDATE session_games SET player_count_check_status = ? WHERE session_id = ? AND id = ?').run(
|
||||
status,
|
||||
sessionId,
|
||||
gameId
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shard Monitor] DB update failed:', e.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function startMonitor(sessionId, gameId, roomCode, maxPlayers = 8) {
|
||||
const monitorKey = `${sessionId}-${gameId}`;
|
||||
|
||||
if (activeShards.has(monitorKey)) {
|
||||
console.log(`[Shard Monitor] Already monitoring ${monitorKey}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[Shard Monitor] Starting monitor for room ${roomCode} (${monitorKey})`);
|
||||
|
||||
const roomInfo = await getRoomInfo(roomCode);
|
||||
if (!roomInfo.exists) {
|
||||
console.log(`[Shard Monitor] Room ${roomCode} not found`);
|
||||
const onEvent = broadcastAndPersist(sessionId, gameId);
|
||||
onEvent('room.disconnected', {
|
||||
sessionId,
|
||||
gameId,
|
||||
roomCode,
|
||||
reason: 'room_not_found',
|
||||
finalPlayerCount: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const onEvent = broadcastAndPersist(sessionId, gameId);
|
||||
|
||||
try {
|
||||
db.prepare('UPDATE session_games SET player_count_check_status = ? WHERE session_id = ? AND id = ?').run(
|
||||
'monitoring',
|
||||
sessionId,
|
||||
gameId
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('[Shard Monitor] DB update failed:', e.message);
|
||||
}
|
||||
|
||||
const client = new EcastShardClient({
|
||||
sessionId,
|
||||
gameId,
|
||||
roomCode,
|
||||
maxPlayers: roomInfo.maxPlayers || maxPlayers,
|
||||
onEvent,
|
||||
});
|
||||
|
||||
activeShards.set(monitorKey, client);
|
||||
|
||||
try {
|
||||
await client.connect(roomInfo);
|
||||
} catch (e) {
|
||||
console.error(`[Shard Monitor] Failed to connect to room ${roomCode}:`, e.message);
|
||||
activeShards.delete(monitorKey);
|
||||
onEvent('room.disconnected', {
|
||||
sessionId,
|
||||
gameId,
|
||||
roomCode,
|
||||
reason: 'connection_failed',
|
||||
finalPlayerCount: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function stopMonitor(sessionId, gameId) {
|
||||
const monitorKey = `${sessionId}-${gameId}`;
|
||||
const client = activeShards.get(monitorKey);
|
||||
|
||||
if (client) {
|
||||
client.manuallyStopped = true;
|
||||
client.disconnect();
|
||||
activeShards.delete(monitorKey);
|
||||
|
||||
const game = db
|
||||
.prepare('SELECT player_count_check_status FROM session_games WHERE session_id = ? AND id = ?')
|
||||
.get(sessionId, gameId);
|
||||
|
||||
if (game && game.player_count_check_status !== 'completed' && game.player_count_check_status !== 'failed') {
|
||||
db.prepare('UPDATE session_games SET player_count_check_status = ? WHERE session_id = ? AND id = ?').run(
|
||||
'stopped',
|
||||
sessionId,
|
||||
gameId
|
||||
);
|
||||
}
|
||||
|
||||
client.onEvent('room.disconnected', {
|
||||
sessionId,
|
||||
gameId,
|
||||
roomCode: client.roomCode,
|
||||
reason: 'manually_stopped',
|
||||
finalPlayerCount: client.playerCount,
|
||||
});
|
||||
|
||||
console.log(`[Shard Monitor] Stopped monitor for ${monitorKey}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanupAllShards() {
|
||||
for (const [, client] of activeShards) {
|
||||
client.manuallyStopped = true;
|
||||
client.disconnect();
|
||||
}
|
||||
activeShards.clear();
|
||||
console.log('[Shard Monitor] Cleaned up all active shards');
|
||||
}
|
||||
|
||||
module.exports = { EcastShardClient, startMonitor, stopMonitor, cleanupAllShards };
|
||||
|
||||
@@ -376,6 +376,22 @@ describe('EcastShardClient', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('module exports', () => {
|
||||
const { startMonitor, stopMonitor, cleanupAllShards } = require('../../backend/utils/ecast-shard-client');
|
||||
|
||||
test('startMonitor is exported', () => {
|
||||
expect(typeof startMonitor).toBe('function');
|
||||
});
|
||||
|
||||
test('stopMonitor is exported', () => {
|
||||
expect(typeof stopMonitor).toBe('function');
|
||||
});
|
||||
|
||||
test('cleanupAllShards is exported', () => {
|
||||
expect(typeof cleanupAllShards).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleError with code 2027', () => {
|
||||
test('marks game as finished and emits events on room-closed error', () => {
|
||||
const events = [];
|
||||
|
||||
Reference in New Issue
Block a user