Remove obsolete GameProcess.js and simplify TimerManager to stub

Co-authored-by: AlecM33 <24642328+AlecM33@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-24 03:40:27 +00:00
parent ae7cf5cbeb
commit 6cead03acd
5 changed files with 17 additions and 94 deletions

View File

@@ -220,9 +220,10 @@ const Events = [
id: EVENT_IDS.END_GAME,
stateChange: async (game, socketArgs, vars) => {
game.status = STATUS.ENDED;
if (game.hasTimer && vars.timerManager.timerThreads[game.accessCode]) {
vars.logger.trace('KILLING TIMER PROCESS FOR ENDED GAME ' + game.accessCode);
vars.timerManager.timerThreads[game.accessCode].kill();
if (game.hasTimer && vars.gameManager.timers[game.accessCode]) {
vars.logger.trace('STOPPING TIMER FOR ENDED GAME ' + game.accessCode);
vars.gameManager.timers[game.accessCode].stopTimer();
delete vars.gameManager.timers[game.accessCode];
}
for (const person of game.people) {
person.revealed = true;

View File

@@ -1,53 +0,0 @@
const { GAME_PROCESS_COMMANDS, PRIMITIVES } = require('../config/globals');
const ServerTimer = require('./ServerTimer.js');
let timer;
// This is a subprocess spawned by logic in the TimerManager module.
process.on('message', (msg) => {
const logger = require('./Logger')(msg.logLevel);
switch (msg.command) {
case GAME_PROCESS_COMMANDS.START_TIMER:
logger.trace('CHILD PROCESS ' + msg.accessCode + ': START TIMER');
timer = new ServerTimer(
msg.hours,
msg.minutes,
PRIMITIVES.CLOCK_TICK_INTERVAL_MILLIS,
logger
);
timer.runTimer().then(() => {
logger.debug('Timer finished for ' + msg.accessCode);
process.send({ command: GAME_PROCESS_COMMANDS.END_TIMER });
process.exit(0);
});
break;
case GAME_PROCESS_COMMANDS.PAUSE_TIMER:
timer.stopTimer();
logger.trace('CHILD PROCESS ' + msg.accessCode + ': PAUSE TIMER');
process.send({ command: GAME_PROCESS_COMMANDS.PAUSE_TIMER, timeRemaining: timer.currentTimeInMillis });
break;
case GAME_PROCESS_COMMANDS.RESUME_TIMER:
timer.resumeTimer().then(() => {
logger.debug('Timer finished for ' + msg.accessCode);
process.send({ command: GAME_PROCESS_COMMANDS.END_TIMER });
process.exit(0);
});
logger.trace('CHILD PROCESS ' + msg.accessCode + ': RESUME TIMER');
process.send({ command: GAME_PROCESS_COMMANDS.RESUME_TIMER, timeRemaining: timer.currentTimeInMillis });
break;
case GAME_PROCESS_COMMANDS.GET_TIME_REMAINING:
logger.trace('CHILD PROCESS ' + msg.accessCode + ': GET TIME REMAINING');
process.send({
command: GAME_PROCESS_COMMANDS.GET_TIME_REMAINING,
timeRemaining: timer.currentTimeInMillis,
socketId: msg.socketId
});
break;
}
});

View File

@@ -1,47 +1,15 @@
const { fork } = require('child_process');
const path = require('path');
const { REDIS_CHANNELS, GAME_PROCESS_COMMANDS } = require('../../config/globals');
// TimerManager is now deprecated - timer logic has been moved to GameManager
// This class is kept as a stub to maintain compatibility with existing dependency injection
class TimerManager {
constructor (logger, instanceId) {
if (TimerManager.instance) {
throw new Error('The server tried to instantiate more than one TimerManager');
}
logger.info('CREATING SINGLETON TIMER MANAGER');
this.timerThreads = {};
logger.info('CREATING SINGLETON TIMER MANAGER (deprecated - timers now managed by GameManager)');
this.logger = logger;
this.subscriber = null;
this.instanceId = instanceId;
TimerManager.instance = this;
}
runTimer = async (game, namespace, eventManager, gameManager) => {
this.logger.debug('running timer for game ' + game.accessCode);
const gameProcess = fork(path.join(__dirname, '../GameProcess.js'));
this.timerThreads[game.accessCode] = gameProcess;
this.logger.debug('game ' + game.accessCode + ' now associated with subProcess ' + gameProcess.pid);
gameProcess.on('message', async (msg) => {
game = await gameManager.getActiveGame(game.accessCode);
await eventManager.handleEventById(msg.command, null, game, msg.socketId, game.accessCode, msg, null, false);
await gameManager.refreshGame(game);
await eventManager.publisher.publish(
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
eventManager.createMessageToPublish(game.accessCode, msg.command, this.instanceId, JSON.stringify(msg))
);
});
gameProcess.on('exit', (code, signal) => {
this.logger.debug('Game timer thread ' + gameProcess.pid + ' exiting with code ' + code + ' - game ' + game.accessCode);
});
gameProcess.send({
command: GAME_PROCESS_COMMANDS.START_TIMER,
accessCode: game.accessCode,
logLevel: this.logger.logLevel,
hours: game.timerParams.hours,
minutes: game.timerParams.minutes
});
game.startTime = new Date().toJSON();
}
}
module.exports = TimerManager;

View File

@@ -56,6 +56,7 @@ describe('Events', () => {
spyOn(eventManager, 'createMessageToPublish').and.stub();
namespace.sockets = new Map();
timerManager.timerThreads = {};
gameManager.timers = {};
});
describe(EVENT_IDS.PLAYER_JOINED, () => {
@@ -363,13 +364,15 @@ describe('Events', () => {
});
it('should end the game and kill the associated timer thread', async () => {
game.hasTimer = true;
timerManager.timerThreads = { ABCD: { kill: () => {} } };
spyOn(timerManager.timerThreads.ABCD, 'kill').and.callThrough();
const mockTimer = { stopTimer: () => {} };
gameManager.timers = { ABCD: mockTimer };
const stopTimerSpy = spyOn(mockTimer, 'stopTimer').and.callThrough();
await Events.find((e) => e.id === EVENT_IDS.END_GAME)
.stateChange(game, { id: 'b', assigned: true }, { gameManager: gameManager, timerManager: timerManager, logger: { trace: () => {} } });
expect(game.status).toEqual(STATUS.ENDED);
expect(game.people.find(p => p.id === 'b').revealed).toBeTrue();
expect(timerManager.timerThreads.ABCD.kill).toHaveBeenCalled();
expect(stopTimerSpy).toHaveBeenCalled();
expect(gameManager.timers.ABCD).toBeUndefined();
});
});
describe('communicate', () => {
@@ -570,6 +573,7 @@ describe('Events', () => {
describe(EVENT_IDS.TIMER_EVENT, () => {
describe('communicate', () => {
it('should publish an event to source timer data if the timer thread is not found', async () => {
game.timerParams = { hours: 1, minutes: 0, paused: true, timeRemaining: 3600000 };
await Events.find((e) => e.id === EVENT_IDS.TIMER_EVENT)
.communicate(game, {}, {
gameManager: gameManager,

View File

@@ -112,6 +112,9 @@ describe('GameManager', () => {
game.moderator = game.people[0];
game.people.find(p => p.id === 'b').userType = USER_TYPES.MODERATOR;
game.hasDedicatedModerator = false;
// Add a mock timer
const mockTimer = { stopTimer: () => {} };
gameManager.timers = { ABCD: mockTimer };
await gameManager.restartGame(game, namespace);