various refactors

This commit is contained in:
AlecM33
2023-08-13 17:51:41 -04:00
parent 29431565b4
commit 0b7dd9f4d7
34 changed files with 1097 additions and 1164 deletions

View File

@@ -3,13 +3,13 @@ const router = express.Router();
const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())).includes('debug');
const logger = require('../modules/Logger')(debugMode);
const eventManager = (require('../modules/singletons/EventManager.js')).instance;
const globals = require('../config/globals.js');
const cors = require('cors');
const { CORS_OPTIONS, CONTENT_TYPE_VALIDATOR } = require('../config/globals');
router.use(cors(globals.CORS));
router.use(cors(CORS_OPTIONS));
router.post('/sockets/broadcast', (req, res, next) => {
globals.CONTENT_TYPE_VALIDATOR(req, res, next);
CONTENT_TYPE_VALIDATOR(req, res, next);
});
// TODO: implement client-side display of this message.

View File

@@ -4,8 +4,8 @@ const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())
const logger = require('../modules/Logger')(debugMode);
const GameManager = require('../modules/singletons/GameManager.js');
const rateLimit = require('express-rate-limit').default;
const globals = require('../config/globals.js');
const cors = require('cors');
const { CORS_OPTIONS, CONTENT_TYPE_VALIDATOR, PRIMITIVES, ERROR_MESSAGES, ENVIRONMENTS } = require('../config/globals');
const gameManager = GameManager.instance;
@@ -20,19 +20,19 @@ const gameEndpointLimiter = rateLimit({
legacyHeaders: false
});
router.use(cors(globals.CORS));
router.options('/:code/players', cors(globals.CORS));
router.options('/create', cors(globals.CORS));
router.options('/restart', cors(globals.CORS));
router.use(cors(CORS_OPTIONS));
router.options('/:code/players', cors(CORS_OPTIONS));
router.options('/create', cors(CORS_OPTIONS));
router.options('/restart', cors(CORS_OPTIONS));
router.post('/create', (req, res, next) => {
globals.CONTENT_TYPE_VALIDATOR(req, res, next);
CONTENT_TYPE_VALIDATOR(req, res, next);
});
router.patch('/players', (req, res, next) => {
globals.CONTENT_TYPE_VALIDATOR(req, res, next);
CONTENT_TYPE_VALIDATOR(req, res, next);
});
router.patch('/restart', (req, res, next) => {
globals.CONTENT_TYPE_VALIDATOR(req, res, next);
CONTENT_TYPE_VALIDATOR(req, res, next);
});
router.post('/create', gameEndpointLimiter, function (req, res) {
@@ -43,8 +43,8 @@ router.post('/create', gameEndpointLimiter, function (req, res) {
res.status(201).send(result); // game was created successfully, and access code was returned
}
}).catch((e) => {
if (e === globals.ERROR_MESSAGE.BAD_CREATE_REQUEST) {
res.status(400).send(globals.ERROR_MESSAGE.BAD_CREATE_REQUEST);
if (e === ERROR_MESSAGES.BAD_CREATE_REQUEST) {
res.status(400).send(ERROR_MESSAGES.BAD_CREATE_REQUEST);
}
});
});
@@ -78,7 +78,7 @@ router.patch('/:code/players', async function (req, res) {
} else {
const game = await gameManager.getActiveGame(req.body.accessCode);
if (game) {
const inUseCookie = gameManager.environment === globals.ENVIRONMENT.PRODUCTION ? req.body.localCookie : req.body.sessionCookie;
const inUseCookie = gameManager.environment === ENVIRONMENTS.PRODUCTION ? req.body.localCookie : req.body.sessionCookie;
gameManager.joinGame(game, req.body.playerName, inUseCookie, req.body.joinAsSpectator).then((data) => {
res.status(200).send({ cookie: data, environment: gameManager.environment });
}).catch((data) => {
@@ -103,7 +103,7 @@ router.patch('/:code/restart', async function (req, res) {
} else {
const game = await gameManager.getActiveGame(req.body.accessCode);
if (game) {
gameManager.restartGame(game, gameManager.namespace, req.query.status).then((data) => {
gameManager.restartGame(game, gameManager.namespace).then((data) => {
res.status(200).send();
}).catch((code) => {
res.status(code).send();
@@ -123,11 +123,11 @@ function validateName (name) {
}
function validateCookie (cookie) {
return cookie === null || cookie === false || (typeof cookie === 'string' && cookie.length === globals.INSTANCE_ID_LENGTH);
return cookie === null || cookie === false || (typeof cookie === 'string' && cookie.length === PRIMITIVES.INSTANCE_ID_LENGTH);
}
function validateAccessCode (accessCode) {
return /^[a-zA-Z0-9]+$/.test(accessCode) && accessCode?.length === globals.ACCESS_CODE_LENGTH;
return /^[a-zA-Z0-9]+$/.test(accessCode) && accessCode?.length === PRIMITIVES.ACCESS_CODE_LENGTH;
}
function validateSpectatorFlag (spectatorFlag) {

View File

@@ -1,4 +1,4 @@
const globals = {
const PRIMITIVES = {
ACCESS_CODE_CHAR_POOL: 'BCDFGHJLMNPQRSTVWXYZ23456789',
INSTANCE_ID_CHAR_POOL: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
ACCESS_CODE_LENGTH: 4,
@@ -6,143 +6,169 @@ const globals = {
CLOCK_TICK_INTERVAL_MILLIS: 100,
MAX_CUSTOM_ROLE_NAME_LENGTH: 50,
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 1000,
ALIGNMENT: {
GOOD: 'good',
EVIL: 'evil'
},
REDIS_CHANNELS: {
ACTIVE_GAME_STREAM: 'active_game_stream'
},
CORS: process.env.NODE_ENV?.trim() === 'development'
? {
origin: '*',
optionsSuccessStatus: 200
}
: {
origin: 'https://play-werewolf.app',
optionsSuccessStatus: 200
},
CONTENT_TYPE_VALIDATOR: (req, res, next) => {
req.accepts();
if (req.is('application/json')) {
next();
} else {
res.status(400).send('Request has invalid content type.');
}
},
STALE_GAME_SECONDS: 86400,
SOCKET_EVENTS: {
IN_GAME_MESSAGE: 'inGameMessage'
},
EVENT_IDS: {
NEW_GAME: 'newGame',
FETCH_GAME_STATE: 'fetchGameState',
START_GAME: 'startGame',
PAUSE_TIMER: 'pauseTimer',
RESUME_TIMER: 'resumeTimer',
END_TIMER: 'endTimer',
GET_TIME_REMAINING: 'getTimeRemaining',
SOURCE_TIMER_EVENT: 'sourceTimerEvent',
KILL_PLAYER: 'killPlayer',
REVEAL_PLAYER: 'revealPlayer',
TRANSFER_MODERATOR: 'transferModerator',
CHANGE_NAME: 'changeName',
END_GAME: 'endGame',
RESTART_GAME: 'restartGame',
PLAYER_JOINED: 'playerJoined',
UPDATE_SPECTATORS: 'updateSpectators',
ADD_SPECTATOR: 'addSpectator',
SYNC_GAME_STATE: 'syncGameState',
UPDATE_SOCKET: 'updateSocket',
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod',
TIMER_EVENT: 'timerEvent',
KICK_PERSON: 'kickPerson',
UPDATE_GAME_ROLES: 'updateGameRoles',
LEAVE_ROOM: 'leaveRoom'
},
SYNCABLE_EVENTS: function () {
return [
this.EVENT_IDS.NEW_GAME,
this.EVENT_IDS.START_GAME,
this.EVENT_IDS.KILL_PLAYER,
this.EVENT_IDS.REVEAL_PLAYER,
this.EVENT_IDS.TRANSFER_MODERATOR,
this.EVENT_IDS.END_GAME,
this.EVENT_IDS.RESTART_GAME,
this.EVENT_IDS.PLAYER_JOINED,
this.EVENT_IDS.ADD_SPECTATOR,
this.EVENT_IDS.SYNC_GAME_STATE,
this.EVENT_IDS.UPDATE_SOCKET,
this.EVENT_IDS.FETCH_GAME_STATE,
this.EVENT_IDS.ASSIGN_DEDICATED_MOD,
this.EVENT_IDS.RESUME_TIMER,
this.EVENT_IDS.PAUSE_TIMER,
this.EVENT_IDS.END_TIMER,
this.EVENT_IDS.KICK_PERSON,
this.EVENT_IDS.UPDATE_GAME_ROLES,
this.EVENT_IDS.LEAVE_ROOM
];
},
TIMER_EVENTS: function () {
return [
this.EVENT_IDS.RESUME_TIMER,
this.EVENT_IDS.PAUSE_TIMER,
this.EVENT_IDS.END_TIMER,
this.EVENT_IDS.GET_TIME_REMAINING
];
},
MESSAGES: {
ENTER_NAME: 'Client must enter name.'
},
STATUS: {
LOBBY: 'lobby',
IN_PROGRESS: 'in progress',
ENDED: 'ended'
},
USER_SIGNATURE_LENGTH: 25,
INSTANCE_ID_LENGTH: 75,
USER_TYPES: {
MODERATOR: 'moderator',
PLAYER: 'player',
TEMPORARY_MODERATOR: 'temp mod',
KILLED_PLAYER: 'killed',
KILLED_BOT: 'killed bot',
SPECTATOR: 'spectator',
BOT: 'bot'
},
ERROR_MESSAGE: {
GAME_IS_FULL: 'This game is full',
BAD_CREATE_REQUEST: 'Game has invalid options.',
NO_UNIQUE_ACCESS_CODE: 'Could not generate a unique access code.'
},
EVENTS: {
PLAYER_JOINED: 'playerJoined',
PLAYER_LEFT: 'playerLeft',
SYNC_GAME_STATE: 'syncGameState',
UPDATE_SPECTATORS: 'newSpectator',
BROADCAST: 'broadcast'
},
ENVIRONMENT: {
LOCAL: 'local',
PRODUCTION: 'production'
},
LOG_LEVEL: {
INFO: 'info',
DEBUG: 'debug',
ERROR: 'error',
WARN: 'warn',
TRACE: 'trace'
},
GAME_PROCESS_COMMANDS: {
END_TIMER: 'endTimer',
START_GAME: 'startGame',
START_TIMER: 'startTimer',
PAUSE_TIMER: 'pauseTimer',
RESUME_TIMER: 'resumeTimer',
GET_TIME_REMAINING: 'getTimeRemaining'
},
MOCK_AUTH: 'mock_auth',
MAX_SPECTATORS: 25
MAX_SPECTATORS: 25,
MOCK_AUTH: 'mock_auth'
};
module.exports = globals;
const LOG_LEVEL = {
INFO: 'info',
DEBUG: 'debug',
ERROR: 'error',
WARN: 'warn',
TRACE: 'trace'
};
const ALIGNMENT = {
GOOD: 'good',
EVIL: 'evil'
};
const REDIS_CHANNELS = {
ACTIVE_GAME_STREAM: 'active_game_stream'
};
const CORS_OPTIONS = process.env.NODE_ENV?.trim() === 'development'
? {
origin: '*',
optionsSuccessStatus: 200
}
: {
origin: 'https://play-werewolf.app',
optionsSuccessStatus: 200
};
const CONTENT_TYPE_VALIDATOR = (req, res, next) => {
req.accepts();
if (req.is('application/json')) {
next();
} else {
res.status(400).send('Request has invalid content type.');
}
};
const SOCKET_EVENTS = {
IN_GAME_MESSAGE: 'inGameMessage'
};
const EVENT_IDS = {
NEW_GAME: 'newGame',
FETCH_GAME_STATE: 'fetchGameState',
START_GAME: 'startGame',
PAUSE_TIMER: 'pauseTimer',
RESUME_TIMER: 'resumeTimer',
END_TIMER: 'endTimer',
GET_TIME_REMAINING: 'getTimeRemaining',
SOURCE_TIMER_EVENT: 'sourceTimerEvent',
KILL_PLAYER: 'killPlayer',
REVEAL_PLAYER: 'revealPlayer',
TRANSFER_MODERATOR: 'transferModerator',
CHANGE_NAME: 'changeName',
END_GAME: 'endGame',
RESTART_GAME: 'restartGame',
PLAYER_JOINED: 'playerJoined',
UPDATE_SPECTATORS: 'updateSpectators',
ADD_SPECTATOR: 'addSpectator',
SYNC_GAME_STATE: 'syncGameState',
UPDATE_SOCKET: 'updateSocket',
ASSIGN_DEDICATED_MOD: 'assignDedicatedMod',
TIMER_EVENT: 'timerEvent',
KICK_PERSON: 'kickPerson',
UPDATE_GAME_ROLES: 'updateGameRoles',
LEAVE_ROOM: 'leaveRoom',
BROADCAST: 'broadcast'
};
const SYNCABLE_EVENTS = function () {
return [
EVENT_IDS.NEW_GAME,
EVENT_IDS.START_GAME,
EVENT_IDS.KILL_PLAYER,
EVENT_IDS.REVEAL_PLAYER,
EVENT_IDS.TRANSFER_MODERATOR,
EVENT_IDS.END_GAME,
EVENT_IDS.RESTART_GAME,
EVENT_IDS.PLAYER_JOINED,
EVENT_IDS.ADD_SPECTATOR,
EVENT_IDS.SYNC_GAME_STATE,
EVENT_IDS.UPDATE_SOCKET,
EVENT_IDS.FETCH_GAME_STATE,
EVENT_IDS.ASSIGN_DEDICATED_MOD,
EVENT_IDS.RESUME_TIMER,
EVENT_IDS.PAUSE_TIMER,
EVENT_IDS.END_TIMER,
EVENT_IDS.KICK_PERSON,
EVENT_IDS.UPDATE_GAME_ROLES,
EVENT_IDS.LEAVE_ROOM
];
};
const TIMER_EVENTS = function () {
return [
EVENT_IDS.RESUME_TIMER,
EVENT_IDS.PAUSE_TIMER,
EVENT_IDS.END_TIMER,
EVENT_IDS.GET_TIME_REMAINING
];
};
const MESSAGES = {
ENTER_NAME: 'Client must enter name.'
};
const STATUS = {
LOBBY: 'lobby',
IN_PROGRESS: 'in progress',
ENDED: 'ended'
};
const USER_TYPES = {
MODERATOR: 'moderator',
PLAYER: 'player',
TEMPORARY_MODERATOR: 'temp mod',
KILLED_PLAYER: 'killed',
KILLED_BOT: 'killed bot',
SPECTATOR: 'spectator',
BOT: 'bot'
};
const ERROR_MESSAGES = {
GAME_IS_FULL: 'This game is full',
BAD_CREATE_REQUEST: 'Game has invalid options.',
NO_UNIQUE_ACCESS_CODE: 'Could not generate a unique access code.'
};
const ENVIRONMENTS = {
LOCAL: 'local',
PRODUCTION: 'production'
};
const GAME_PROCESS_COMMANDS = {
END_TIMER: 'endTimer',
START_GAME: 'startGame',
START_TIMER: 'startTimer',
PAUSE_TIMER: 'pauseTimer',
RESUME_TIMER: 'resumeTimer',
GET_TIME_REMAINING: 'getTimeRemaining'
};
module.exports = {
PRIMITIVES,
LOG_LEVEL,
ALIGNMENT,
REDIS_CHANNELS,
CORS_OPTIONS,
CONTENT_TYPE_VALIDATOR,
SOCKET_EVENTS,
EVENT_IDS,
SYNCABLE_EVENTS,
TIMER_EVENTS,
MESSAGES,
STATUS,
USER_TYPES,
ERROR_MESSAGES,
ENVIRONMENTS,
GAME_PROCESS_COMMANDS
};

View File

@@ -1,4 +1,4 @@
const globals = require('../config/globals');
const { ERROR_MESSAGES, PRIMITIVES, ALIGNMENT } = require('../config/globals');
class GameCreationRequest {
constructor (
@@ -24,7 +24,7 @@ class GameCreationRequest {
|| expectedKeys.some((key) => !Object.keys(gameParams).includes(key))
|| !valid(gameParams)
) {
return Promise.reject(globals.ERROR_MESSAGE.BAD_CREATE_REQUEST);
return Promise.reject(ERROR_MESSAGES.BAD_CREATE_REQUEST);
} else {
return Promise.resolve();
}
@@ -37,12 +37,12 @@ class GameCreationRequest {
&& typeof entry === 'object'
&& typeof entry.role === 'string'
&& entry.role.length > 0
&& entry.role.length <= globals.MAX_CUSTOM_ROLE_NAME_LENGTH
&& entry.role.length <= PRIMITIVES.MAX_CUSTOM_ROLE_NAME_LENGTH
&& typeof entry.team === 'string'
&& (entry.team === globals.ALIGNMENT.GOOD || entry.team === globals.ALIGNMENT.EVIL)
&& (entry.team === ALIGNMENT.GOOD || entry.team === ALIGNMENT.EVIL)
&& typeof entry.description === 'string'
&& entry.description.length > 0
&& entry.description.length <= globals.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
&& entry.description.length <= PRIMITIVES.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
&& (!entry.custom || typeof entry.custom === 'boolean')
&& typeof entry.quantity === 'number'
&& entry.quantity >= 0

View File

@@ -1,5 +1,5 @@
// noinspection DuplicatedCode
const globals = require('../config/globals');
const { USER_TYPES } = require('../config/globals');
class Person {
constructor (id, cookie, name, userType, gameRole = null, gameRoleDescription = null, alignment = null, assigned = false) {
@@ -12,7 +12,7 @@ class Person {
this.gameRoleDescription = gameRoleDescription;
this.alignment = alignment;
this.assigned = assigned;
this.out = userType === globals.USER_TYPES.MODERATOR || userType === globals.USER_TYPES.SPECTATOR;
this.out = userType === USER_TYPES.MODERATOR || userType === USER_TYPES.SPECTATOR;
this.killed = false;
this.revealed = false;
this.hasEnteredName = false;

View File

@@ -1,7 +1,6 @@
const globals = require('../config/globals');
const GameStateCurator = require('./GameStateCurator');
const GameCreationRequest = require('../model/GameCreationRequest');
const EVENT_IDS = globals.EVENT_IDS;
const { EVENT_IDS, STATUS, USER_TYPES, GAME_PROCESS_COMMANDS, REDIS_CHANNELS } = require('../config/globals');
const Events = [
{
@@ -12,7 +11,7 @@ const Events = [
},
communicate: async (game, socketArgs, vars) => {
vars.gameManager.namespace.in(game.accessCode).emit(
globals.EVENTS.PLAYER_JOINED,
EVENT_IDS.PLAYER_JOINED,
GameStateCurator.mapPerson(socketArgs),
game.isStartable
);
@@ -87,7 +86,7 @@ const Events = [
},
communicate: async (game, socketArgs, vars) => {
vars.gameManager.namespace.in(game.accessCode).emit(
globals.EVENT_IDS.ADD_SPECTATOR,
EVENT_IDS.ADD_SPECTATOR,
GameStateCurator.mapPerson(socketArgs)
);
}
@@ -117,7 +116,7 @@ const Events = [
communicate: async (game, socketArgs, vars) => {
const matchingPerson = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
if (matchingPerson && vars.gameManager.namespace.sockets.get(matchingPerson.socketId)) {
vars.gameManager.namespace.to(matchingPerson.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
vars.gameManager.namespace.to(matchingPerson.socketId).emit(EVENT_IDS.SYNC_GAME_STATE);
}
}
},
@@ -125,7 +124,7 @@ const Events = [
id: EVENT_IDS.START_GAME,
stateChange: async (game, socketArgs, vars) => {
if (game.isStartable) {
game.status = globals.STATUS.IN_PROGRESS;
game.status = STATUS.IN_PROGRESS;
vars.gameManager.deal(game);
if (game.hasTimer) {
game.timerParams.paused = true;
@@ -137,7 +136,7 @@ const Events = [
if (vars.ackFn) {
vars.ackFn();
}
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.START_GAME);
vars.gameManager.namespace.in(game.accessCode).emit(EVENT_IDS.START_GAME);
}
},
{
@@ -145,9 +144,9 @@ const Events = [
stateChange: async (game, socketArgs, vars) => {
const person = game.people.find((person) => person.id === socketArgs.personId);
if (person && !person.out) {
person.userType = person.userType === globals.USER_TYPES.BOT
? globals.USER_TYPES.KILLED_BOT
: globals.USER_TYPES.KILLED_PLAYER;
person.userType = person.userType === USER_TYPES.BOT
? USER_TYPES.KILLED_BOT
: USER_TYPES.KILLED_PLAYER;
person.out = true;
person.killed = true;
}
@@ -155,7 +154,7 @@ const Events = [
communicate: async (game, socketArgs, vars) => {
const person = game.people.find((person) => person.id === socketArgs.personId);
if (person) {
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, person);
vars.gameManager.namespace.in(game.accessCode).emit(EVENT_IDS.KILL_PLAYER, person);
}
}
},
@@ -171,7 +170,7 @@ const Events = [
const person = game.people.find((person) => person.id === socketArgs.personId);
if (person) {
vars.gameManager.namespace.in(game.accessCode).emit(
globals.EVENT_IDS.REVEAL_PLAYER,
EVENT_IDS.REVEAL_PLAYER,
{
id: person.id,
gameRole: person.gameRole,
@@ -184,7 +183,7 @@ const Events = [
{
id: EVENT_IDS.END_GAME,
stateChange: async (game, socketArgs, vars) => {
game.status = globals.STATUS.ENDED;
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();
@@ -195,7 +194,7 @@ const Events = [
},
communicate: async (game, socketArgs, vars) => {
vars.gameManager.namespace.in(game.accessCode)
.emit(globals.EVENT_IDS.END_GAME, GameStateCurator.mapPeopleForModerator(game.people));
.emit(EVENT_IDS.END_GAME, GameStateCurator.mapPeopleForModerator(game.people));
if (vars.ackFn) {
vars.ackFn();
}
@@ -208,14 +207,14 @@ const Events = [
const toTransferTo = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
if (currentModerator) {
if (currentModerator.gameRole) {
currentModerator.userType = globals.USER_TYPES.KILLED_PLAYER;
currentModerator.userType = USER_TYPES.KILLED_PLAYER;
} else {
currentModerator.userType = globals.USER_TYPES.SPECTATOR;
currentModerator.userType = USER_TYPES.SPECTATOR;
}
game.previousModeratorId = currentModerator.id;
}
if (toTransferTo) {
toTransferTo.userType = globals.USER_TYPES.MODERATOR;
toTransferTo.userType = USER_TYPES.MODERATOR;
game.currentModeratorId = toTransferTo.id;
}
},
@@ -223,7 +222,7 @@ const Events = [
if (vars.ackFn) {
vars.ackFn();
}
vars.gameManager.namespace.to(game.accessCode).emit(globals.EVENT_IDS.SYNC_GAME_STATE);
vars.gameManager.namespace.to(game.accessCode).emit(EVENT_IDS.SYNC_GAME_STATE);
}
},
{
@@ -233,10 +232,10 @@ const Events = [
const toTransferTo = vars.gameManager.findPersonByField(game, 'id', socketArgs.personId);
if (currentModerator && toTransferTo) {
if (currentModerator.id !== toTransferTo.id) {
currentModerator.userType = globals.USER_TYPES.PLAYER;
currentModerator.userType = USER_TYPES.PLAYER;
}
toTransferTo.userType = globals.USER_TYPES.MODERATOR;
toTransferTo.userType = USER_TYPES.MODERATOR;
toTransferTo.out = true;
toTransferTo.killed = true;
game.previousModeratorId = currentModerator.id;
@@ -247,14 +246,14 @@ const Events = [
const moderator = vars.gameManager.findPersonByField(game, 'id', game.currentModeratorId);
const moderatorSocket = vars.gameManager.namespace.sockets.get(moderator?.socketId);
if (moderator && moderatorSocket) {
vars.gameManager.namespace.to(moderator.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
moderatorSocket.to(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, moderator);
vars.gameManager.namespace.to(moderator.socketId).emit(EVENT_IDS.SYNC_GAME_STATE);
moderatorSocket.to(game.accessCode).emit(EVENT_IDS.KILL_PLAYER, moderator);
} else {
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.KILL_PLAYER, moderator);
vars.gameManager.namespace.in(game.accessCode).emit(EVENT_IDS.KILL_PLAYER, moderator);
}
const previousModerator = vars.gameManager.findPersonByField(game, 'id', game.previousModeratorId);
if (previousModerator && previousModerator.id !== moderator.id && vars.gameManager.namespace.sockets.get(previousModerator.socketId)) {
vars.gameManager.namespace.to(previousModerator.socketId).emit(globals.EVENTS.SYNC_GAME_STATE);
vars.gameManager.namespace.to(previousModerator.socketId).emit(EVENT_IDS.SYNC_GAME_STATE);
}
}
},
@@ -274,7 +273,7 @@ const Events = [
if (vars.ackFn) {
vars.ackFn();
}
vars.gameManager.namespace.in(game.accessCode).emit(globals.EVENT_IDS.RESTART_GAME);
vars.gameManager.namespace.in(game.accessCode).emit(EVENT_IDS.RESTART_GAME);
}
},
{
@@ -294,7 +293,7 @@ const Events = [
const socket = vars.gameManager.namespace.sockets.get(vars.requestingSocketId);
if (socket) {
vars.gameManager.namespace.to(socket.id).emit(
globals.GAME_PROCESS_COMMANDS.GET_TIME_REMAINING,
GAME_PROCESS_COMMANDS.GET_TIME_REMAINING,
game.timerParams.timeRemaining,
game.timerParams.paused
);
@@ -302,10 +301,10 @@ const Events = [
}
} else { // we need to consult another container for the timer data
await vars.eventManager.publisher?.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
vars.eventManager.createMessageToPublish(
game.accessCode,
globals.EVENT_IDS.SOURCE_TIMER_EVENT,
EVENT_IDS.SOURCE_TIMER_EVENT,
vars.instanceId,
JSON.stringify({ socketId: vars.requestingSocketId, timerEventSubtype: vars.timerEventSubtype })
)
@@ -330,7 +329,7 @@ const Events = [
});
} else {
await vars.eventManager.publisher.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
vars.eventManager.createMessageToPublish(
game.accessCode,
socketArgs.timerEventSubtype,
@@ -353,7 +352,7 @@ const Events = [
game.timerParams.timeRemaining = 0;
},
communicate: async (game, socketArgs, vars) => {
vars.gameManager.namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.END_TIMER);
vars.gameManager.namespace.in(game.accessCode).emit(GAME_PROCESS_COMMANDS.END_TIMER);
}
},
{
@@ -363,7 +362,7 @@ const Events = [
game.timerParams.timeRemaining = socketArgs.timeRemaining;
},
communicate: async (game, socketArgs, vars) => {
vars.gameManager.namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER, socketArgs.timeRemaining);
vars.gameManager.namespace.in(game.accessCode).emit(GAME_PROCESS_COMMANDS.PAUSE_TIMER, socketArgs.timeRemaining);
}
},
{
@@ -373,7 +372,7 @@ const Events = [
game.timerParams.timeRemaining = socketArgs.timeRemaining;
},
communicate: async (game, socketArgs, vars) => {
vars.gameManager.namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.RESUME_TIMER, socketArgs.timeRemaining);
vars.gameManager.namespace.in(game.accessCode).emit(GAME_PROCESS_COMMANDS.RESUME_TIMER, socketArgs.timeRemaining);
}
},
{
@@ -382,7 +381,7 @@ const Events = [
communicate: async (game, socketArgs, vars) => {
const socket = vars.gameManager.namespace.sockets.get(socketArgs.socketId);
if (socket) {
vars.gameManager.namespace.to(socket.id).emit(globals.GAME_PROCESS_COMMANDS.GET_TIME_REMAINING, socketArgs.timeRemaining, game.timerParams.paused);
vars.gameManager.namespace.to(socket.id).emit(GAME_PROCESS_COMMANDS.GET_TIME_REMAINING, socketArgs.timeRemaining, game.timerParams.paused);
}
}
}

View File

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

View File

@@ -1,4 +1,4 @@
const globals = require('../config/globals');
const { USER_TYPES, STATUS } = require('../config/globals');
/* The purpose of this component is to only return the game state information that is necessary. For example, we only
want to return player role information to moderators. This avoids any possibility of a player having access to
@@ -12,7 +12,7 @@ const GameStateCurator = {
mapPeopleForModerator: (people) => {
return people
.filter((person) => {
return person.assigned === true || (person.userType === globals.USER_TYPES.SPECTATOR || person.userType === globals.USER_TYPES.MODERATOR);
return person.assigned === true || (person.userType === USER_TYPES.SPECTATOR || person.userType === USER_TYPES.MODERATOR);
})
.map((person) => ({
name: person.name,
@@ -45,7 +45,7 @@ const GameStateCurator = {
};
function getGameStateBasedOnPermissions (game, person) {
const client = game.status === globals.STATUS.LOBBY // people won't be able to know their role until past the lobby stage.
const client = game.status === STATUS.LOBBY // people won't be able to know their role until past the lobby stage.
? { name: person.name, hasEnteredName: person.hasEnteredName, id: person.id, cookie: person.cookie, userType: person.userType }
: {
name: person.name,
@@ -61,7 +61,7 @@ function getGameStateBasedOnPermissions (game, person) {
killed: person.killed
};
switch (person.userType) {
case globals.USER_TYPES.MODERATOR:
case USER_TYPES.MODERATOR:
return {
accessCode: game.accessCode,
status: game.status,
@@ -73,10 +73,10 @@ function getGameStateBasedOnPermissions (game, person) {
timerParams: game.timerParams,
isStartable: game.isStartable
};
case globals.USER_TYPES.TEMPORARY_MODERATOR:
case globals.USER_TYPES.SPECTATOR:
case globals.USER_TYPES.PLAYER:
case globals.USER_TYPES.KILLED_PLAYER:
case USER_TYPES.TEMPORARY_MODERATOR:
case USER_TYPES.SPECTATOR:
case USER_TYPES.PLAYER:
case USER_TYPES.KILLED_PLAYER:
return {
accessCode: game.accessCode,
status: game.status,
@@ -86,7 +86,7 @@ function getGameStateBasedOnPermissions (game, person) {
gameSize: game.gameSize,
people: game.people
.filter((person) => {
return person.assigned === true || person.userType === globals.USER_TYPES.SPECTATOR;
return person.assigned === true || person.userType === USER_TYPES.SPECTATOR;
})
.map((filteredPerson) => GameStateCurator.mapPerson(filteredPerson)),
timerParams: game.timerParams,

View File

@@ -1,6 +1,6 @@
const globals = require('../config/globals');
const { LOG_LEVEL } = require('../config/globals');
module.exports = function (logLevel = globals.LOG_LEVEL.INFO) {
module.exports = function (logLevel = LOG_LEVEL.INFO) {
return {
logLevel: logLevel,
info (message = '') {
@@ -10,7 +10,7 @@ module.exports = function (logLevel = globals.LOG_LEVEL.INFO) {
error (message = '') {
if (
logLevel === globals.LOG_LEVEL.INFO
logLevel === LOG_LEVEL.INFO
) { return; }
const now = new Date();
console.error('ERROR ', now.toGMTString(), ': ', message);
@@ -18,25 +18,25 @@ module.exports = function (logLevel = globals.LOG_LEVEL.INFO) {
warn (message = '') {
if (
logLevel === globals.LOG_LEVEL.INFO
|| logLevel === globals.LOG_LEVEL.ERROR
logLevel === LOG_LEVEL.INFO
|| logLevel === LOG_LEVEL.ERROR
) return;
const now = new Date();
console.error('WARN ', now.toGMTString(), ': ', message);
},
debug (message = '') {
if (logLevel === globals.LOG_LEVEL.INFO || logLevel === globals.LOG_LEVEL.ERROR || logLevel === globals.LOG_LEVEL.WARN) return;
if (logLevel === LOG_LEVEL.INFO || logLevel === LOG_LEVEL.ERROR || logLevel === LOG_LEVEL.WARN) return;
const now = new Date();
console.debug('DEBUG ', now.toGMTString(), ': ', message);
},
trace (message = '') {
if (
logLevel === globals.LOG_LEVEL.INFO
|| logLevel === globals.LOG_LEVEL.WARN
|| logLevel === globals.LOG_LEVEL.DEBUG
|| logLevel === globals.LOG_LEVEL.ERROR
logLevel === LOG_LEVEL.INFO
|| logLevel === LOG_LEVEL.WARN
|| logLevel === LOG_LEVEL.DEBUG
|| logLevel === LOG_LEVEL.ERROR
) return;
const now = new Date();

View File

@@ -1,4 +1,4 @@
const LOG_LEVEL = require('../config/globals').LOG_LEVEL;
const { LOG_LEVEL, ENVIRONMENTS } = require('../config/globals');
const http = require('http');
const https = require('https');
const path = require('path');
@@ -7,7 +7,6 @@ const crypto = require('crypto');
const EventManager = require('./singletons/EventManager.js');
const GameManager = require('./singletons/GameManager.js');
const TimerManager = require('./singletons/TimerManager.js');
const { ENVIRONMENT } = require('../config/globals.js');
const rateLimit = require('express-rate-limit').default;
const ServerBootstrapper = {
@@ -17,8 +16,8 @@ const ServerBootstrapper = {
timerManager: new TimerManager(logger, instanceId),
eventManager: new EventManager(logger, instanceId),
gameManager: process.env.NODE_ENV.trim() === 'development'
? new GameManager(logger, ENVIRONMENT.LOCAL, instanceId)
: new GameManager(logger, ENVIRONMENT.PRODUCTION, instanceId)
? new GameManager(logger, ENVIRONMENTS.LOCAL, instanceId)
: new GameManager(logger, ENVIRONMENTS.PRODUCTION, instanceId)
};
},
@@ -114,7 +113,7 @@ const ServerBootstrapper = {
});
// API endpoints
app.use('/api/games', standardRateLimit, require('../api/GamesAPI'));
app.use('/api/games', standardRateLimit, require('../api/RoomsAPI'));
app.use('/api/admin', (req, res, next) => {
if (isAuthorized(req)) {
next();

View File

@@ -1,7 +1,7 @@
const globals = require('../../config/globals');
const { RateLimiterMemory } = require('rate-limiter-flexible');
const redis = require('redis');
const Events = require('../Events');
const { EVENT_IDS, REDIS_CHANNELS, PRIMITIVES, SOCKET_EVENTS, TIMER_EVENTS, SYNCABLE_EVENTS } = require('../../config/globals');
class EventManager {
constructor (logger, instanceId) {
@@ -20,7 +20,7 @@ class EventManager {
}
broadcast = (message) => {
this.io?.emit(globals.EVENTS.BROADCAST, message);
this.io?.emit(EVENT_IDS.BROADCAST, message);
};
createRedisPublisher = async () => {
@@ -53,7 +53,7 @@ class EventManager {
throw new Error('UNABLE TO CONNECT TO REDIS because: ' + e);
}
await this.subscriber.subscribe(globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM, async (message) => {
await this.subscriber.subscribe(REDIS_CHANNELS.ACTIVE_GAME_STREAM, async (message) => {
this.logger.debug('MESSAGE: ' + message);
let messageComponents, args;
try {
@@ -64,7 +64,7 @@ class EventManager {
}
args = JSON.parse(
message.slice(
message.indexOf(messageComponents[messageComponents.length - 1]) + (globals.INSTANCE_ID_LENGTH + 1)
message.indexOf(messageComponents[messageComponents.length - 1]) + (PRIMITIVES.INSTANCE_ID_LENGTH + 1)
)
);
} catch (e) {
@@ -133,12 +133,12 @@ class EventManager {
};
registerSocketHandler = (namespace, socket, gameManager) => {
socket.on(globals.SOCKET_EVENTS.IN_GAME_MESSAGE, async (eventId, accessCode, args = null, ackFn = null) => {
socket.on(SOCKET_EVENTS.IN_GAME_MESSAGE, async (eventId, accessCode, args = null, ackFn = null) => {
const game = await gameManager.getActiveGame(accessCode);
if (game) {
if (globals.TIMER_EVENTS().includes(eventId)) {
if (TIMER_EVENTS().includes(eventId)) {
await this.handleEventById(
globals.EVENT_IDS.TIMER_EVENT,
EVENT_IDS.TIMER_EVENT,
null,
game,
socket.id,
@@ -160,10 +160,10 @@ class EventManager {
handleAndSyncSocketEvent = async (eventId, game, socket, socketArgs, ackFn) => {
await this.handleEventById(eventId, null, game, socket?.id, game.accessCode, socketArgs, ackFn, false);
/* This server should publish events initiated by a connected socket to Redis for consumption by other instances. */
if (globals.SYNCABLE_EVENTS().includes(eventId)) {
if (SYNCABLE_EVENTS().includes(eventId)) {
await this.gameManager.refreshGame(game);
await this.publisher?.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
this.createMessageToPublish(game.accessCode, eventId, this.instanceId, JSON.stringify(socketArgs))
);
}
@@ -194,7 +194,7 @@ class EventManager {
timerEventSubtype: timerEventSubtype
};
if (event) {
if (!syncOnly || eventId === globals.EVENT_IDS.RESTART_GAME) {
if (!syncOnly || eventId === EVENT_IDS.RESTART_GAME) {
await event.stateChange(game, socketArgs, additionalVars);
}
await event.communicate(game, socketArgs, additionalVars);

View File

@@ -1,4 +1,12 @@
const globals = require('../../config/globals');
const {
STATUS,
PRIMITIVES,
ERROR_MESSAGES,
GAME_PROCESS_COMMANDS,
USER_TYPES,
EVENT_IDS,
REDIS_CHANNELS
} = require('../../config/globals');
const Game = require('../../model/Game');
const Person = require('../../model/Person');
const GameStateCurator = require('../GameStateCurator');
@@ -62,9 +70,9 @@ class GameManager {
gameParams.hasDedicatedModerator,
gameParams.isTestGame
);
const newAccessCode = await this.generateAccessCode(globals.ACCESS_CODE_CHAR_POOL);
const newAccessCode = await this.generateAccessCode(PRIMITIVES.ACCESS_CODE_CHAR_POOL);
if (newAccessCode === null) {
return Promise.reject(globals.ERROR_MESSAGE.NO_UNIQUE_ACCESS_CODE);
return Promise.reject(ERROR_MESSAGES.NO_UNIQUE_ACCESS_CODE);
}
const moderator = initializeModerator(req.moderatorName, req.hasDedicatedModerator);
moderator.assigned = true;
@@ -75,7 +83,7 @@ class GameManager {
}
const newGame = new Game(
newAccessCode,
globals.STATUS.LOBBY,
STATUS.LOBBY,
null,
req.deck,
req.hasTimer,
@@ -88,7 +96,7 @@ class GameManager {
);
newGame.people = initializePeopleForGame(req.deck, moderator, this.shuffle, req.isTestGame, newGame.gameSize);
await this.eventManager.publisher.set(newAccessCode, JSON.stringify(newGame), {
EX: globals.STALE_GAME_SECONDS
EX: PRIMITIVES.STALE_GAME_SECONDS
});
return Promise.resolve({ accessCode: newAccessCode, cookie: moderator.cookie, environment: this.environment });
}).catch((message) => {
@@ -103,7 +111,7 @@ class GameManager {
if (thread && !thread.killed) {
this.logger.debug('Timer thread found for game ' + game.accessCode);
thread.send({
command: globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER,
command: GAME_PROCESS_COMMANDS.PAUSE_TIMER,
accessCode: game.accessCode,
logLevel: this.logger.logLevel
});
@@ -115,7 +123,7 @@ class GameManager {
if (thread && !thread.killed) {
this.logger.debug('Timer thread found for game ' + game.accessCode);
thread.send({
command: globals.GAME_PROCESS_COMMANDS.RESUME_TIMER,
command: GAME_PROCESS_COMMANDS.RESUME_TIMER,
accessCode: game.accessCode,
logLevel: this.logger.logLevel
});
@@ -127,14 +135,14 @@ class GameManager {
const thread = this.timerManager.timerThreads[game.accessCode];
if (thread && (!thread.killed && thread.exitCode === null)) {
thread.send({
command: globals.GAME_PROCESS_COMMANDS.GET_TIME_REMAINING,
command: GAME_PROCESS_COMMANDS.GET_TIME_REMAINING,
accessCode: game.accessCode,
socketId: socketId,
logLevel: this.logger.logLevel
});
} else if (thread) {
if (game.timerParams && game.timerParams.timeRemaining === 0) {
this.namespace.to(socketId).emit(globals.GAME_PROCESS_COMMANDS.GET_TIME_REMAINING, game.timerParams.timeRemaining, game.timerParams.paused);
this.namespace.to(socketId).emit(GAME_PROCESS_COMMANDS.GET_TIME_REMAINING, game.timerParams.timeRemaining, game.timerParams.paused);
}
}
}
@@ -154,9 +162,9 @@ class GameManager {
let codeDigits, accessCode;
let attempts = 0;
while (!accessCode || ((await this.eventManager.publisher.keys('*')).includes(accessCode)
&& attempts < globals.ACCESS_CODE_GENERATION_ATTEMPTS)) {
&& attempts < PRIMITIVES.ACCESS_CODE_GENERATION_ATTEMPTS)) {
codeDigits = [];
let iterations = globals.ACCESS_CODE_LENGTH;
let iterations = PRIMITIVES.ACCESS_CODE_LENGTH;
while (iterations > 0) {
iterations --;
codeDigits.push(charPool[getRandomInt(charCount)]);
@@ -178,7 +186,7 @@ class GameManager {
return Promise.reject({ status: 400, reason: 'This name is taken.' });
}
if (joinAsSpectator
&& game.people.filter(person => person.userType === globals.USER_TYPES.SPECTATOR).length === globals.MAX_SPECTATORS
&& game.people.filter(person => person.userType === USER_TYPES.SPECTATOR).length === PRIMITIVES.MAX_SPECTATORS
) {
return Promise.reject({ status: 400, reason: 'There are too many people already spectating.' });
} else if (joinAsSpectator || this.isGameStartable(game)) {
@@ -196,7 +204,7 @@ class GameManager {
createRandomId(),
createRandomId(),
name,
globals.USER_TYPES.PLAYER,
USER_TYPES.PLAYER,
null,
null,
null,
@@ -208,15 +216,15 @@ class GameManager {
game.isStartable = this.isGameStartable(game);
await this.refreshGame(game);
this.namespace.in(game.accessCode).emit(
globals.EVENTS.PLAYER_JOINED,
EVENT_IDS.PLAYER_JOINED,
GameStateCurator.mapPerson(moderator || newPlayer),
game.isStartable
);
await this.eventManager.publisher?.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
this.eventManager.createMessageToPublish(
game.accessCode,
globals.EVENT_IDS.PLAYER_JOINED,
EVENT_IDS.PLAYER_JOINED,
this.instanceId,
JSON.stringify(moderator || newPlayer)
)
@@ -237,7 +245,7 @@ class GameManager {
return cards;
}
restartGame = async (game, namespace, status = globals.STATUS.IN_PROGRESS) => {
restartGame = async (game, namespace) => {
// kill any outstanding timer threads
const subProcess = this.timerManager.timerThreads[game.accessCode];
if (subProcess) {
@@ -250,16 +258,16 @@ class GameManager {
}
for (let i = 0; i < game.people.length; i ++) {
if (game.people[i].userType === globals.USER_TYPES.KILLED_PLAYER) {
game.people[i].userType = globals.USER_TYPES.PLAYER;
if (game.people[i].userType === USER_TYPES.KILLED_PLAYER) {
game.people[i].userType = USER_TYPES.PLAYER;
game.people[i].out = false;
}
if (game.people[i].userType === globals.USER_TYPES.KILLED_BOT) {
game.people[i].userType = globals.USER_TYPES.BOT;
if (game.people[i].userType === USER_TYPES.KILLED_BOT) {
game.people[i].userType = USER_TYPES.BOT;
game.people[i].out = false;
}
if (game.people[i].gameRole && game.people[i].id === game.currentModeratorId && game.people[i].userType === globals.USER_TYPES.MODERATOR) {
game.people[i].userType = globals.USER_TYPES.TEMPORARY_MODERATOR;
if (game.people[i].gameRole && game.people[i].id === game.currentModeratorId && game.people[i].userType === USER_TYPES.MODERATOR) {
game.people[i].userType = USER_TYPES.TEMPORARY_MODERATOR;
game.people[i].out = false;
}
game.people[i].revealed = false;
@@ -270,19 +278,19 @@ class GameManager {
game.people[i].customRole = null;
}
game.status = globals.STATUS.LOBBY;
game.status = STATUS.LOBBY;
await this.refreshGame(game);
await this.eventManager.publisher?.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
this.eventManager.createMessageToPublish(
game.accessCode,
globals.EVENT_IDS.RESTART_GAME,
EVENT_IDS.RESTART_GAME,
this.instanceId,
'{}'
)
);
namespace.in(game.accessCode).emit(globals.EVENT_IDS.RESTART_GAME);
namespace.in(game.accessCode).emit(EVENT_IDS.RESTART_GAME);
};
/*
@@ -305,9 +313,9 @@ class GameManager {
deal = (game) => {
const cards = this.prepareDeck(game.deck);
let i = 0;
for (const person of game.people.filter(person => person.userType === globals.USER_TYPES.PLAYER
|| person.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|| person.userType === globals.USER_TYPES.BOT)
for (const person of game.people.filter(person => person.userType === USER_TYPES.PLAYER
|| person.userType === USER_TYPES.TEMPORARY_MODERATOR
|| person.userType === USER_TYPES.BOT)
) {
person.gameRole = cards[i].role;
person.customRole = cards[i].custom;
@@ -318,9 +326,9 @@ class GameManager {
}
isGameStartable = (game) => {
return game.people.filter(person => person.userType === globals.USER_TYPES.PLAYER
|| person.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
|| person.userType === globals.USER_TYPES.BOT).length === game.gameSize;
return game.people.filter(person => person.userType === USER_TYPES.PLAYER
|| person.userType === USER_TYPES.TEMPORARY_MODERATOR
|| person.userType === USER_TYPES.BOT).length === game.gameSize;
}
findPersonByField = (game, fieldName, value) => {
@@ -334,8 +342,8 @@ function getRandomInt (max) {
function initializeModerator (name, hasDedicatedModerator) {
const userType = hasDedicatedModerator
? globals.USER_TYPES.MODERATOR
: globals.USER_TYPES.TEMPORARY_MODERATOR;
? USER_TYPES.MODERATOR
: USER_TYPES.TEMPORARY_MODERATOR;
return new Person(createRandomId(), createRandomId(), name, userType);
}
@@ -343,7 +351,7 @@ function initializePeopleForGame (uniqueRoles, moderator, shuffle, isTestGame, g
const people = [];
if (isTestGame) {
let j = 0;
const number = moderator.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
const number = moderator.userType === USER_TYPES.TEMPORARY_MODERATOR
? gameSize - 1
: gameSize;
while (j < number) {
@@ -351,7 +359,7 @@ function initializePeopleForGame (uniqueRoles, moderator, shuffle, isTestGame, g
createRandomId(),
createRandomId(),
UsernameGenerator.generate(),
globals.USER_TYPES.BOT,
USER_TYPES.BOT,
null,
null,
null,
@@ -369,8 +377,8 @@ function initializePeopleForGame (uniqueRoles, moderator, shuffle, isTestGame, g
function createRandomId () {
let id = '';
for (let i = 0; i < globals.INSTANCE_ID_LENGTH; i ++) {
id += globals.INSTANCE_ID_CHAR_POOL[Math.floor(Math.random() * globals.INSTANCE_ID_CHAR_POOL.length)];
for (let i = 0; i < PRIMITIVES.INSTANCE_ID_LENGTH; i ++) {
id += PRIMITIVES.INSTANCE_ID_CHAR_POOL[Math.floor(Math.random() * PRIMITIVES.INSTANCE_ID_CHAR_POOL.length)];
}
return id;
}
@@ -385,21 +393,21 @@ async function addSpectator (game, name, logger, namespace, eventManager, instan
createRandomId(),
createRandomId(),
name,
globals.USER_TYPES.SPECTATOR
USER_TYPES.SPECTATOR
);
spectator.assigned = true;
logger.trace('new spectator: ' + spectator.name);
game.people.push(spectator);
await refreshGame(game);
namespace.in(game.accessCode).emit(
globals.EVENT_IDS.ADD_SPECTATOR,
EVENT_IDS.ADD_SPECTATOR,
GameStateCurator.mapPerson(spectator)
);
await eventManager.publisher.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
eventManager.createMessageToPublish(
game.accessCode,
globals.EVENT_IDS.ADD_SPECTATOR,
EVENT_IDS.ADD_SPECTATOR,
instanceId,
JSON.stringify(GameStateCurator.mapPerson(spectator))
)

View File

@@ -1,6 +1,6 @@
const { fork } = require('child_process');
const path = require('path');
const globals = require('../../config/globals');
const { REDIS_CHANNELS, GAME_PROCESS_COMMANDS } = require('../../config/globals');
class TimerManager {
constructor (logger, instanceId) {
@@ -25,7 +25,7 @@ class TimerManager {
await eventManager.handleEventById(msg.command, null, game, msg.socketId, game.accessCode, msg, null, false);
await gameManager.refreshGame(game);
await eventManager.publisher.publish(
globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM,
REDIS_CHANNELS.ACTIVE_GAME_STREAM,
eventManager.createMessageToPublish(game.accessCode, msg.command, this.instanceId, JSON.stringify(msg))
);
});
@@ -34,7 +34,7 @@ class TimerManager {
this.logger.debug('Game timer thread ' + gameProcess.pid + ' exiting with code ' + code + ' - game ' + game.accessCode);
});
gameProcess.send({
command: globals.GAME_PROCESS_COMMANDS.START_TIMER,
command: GAME_PROCESS_COMMANDS.START_TIMER,
accessCode: game.accessCode,
logLevel: this.logger.logLevel,
hours: game.timerParams.hours,