import arg from "arg"; import { Logger } from "tslog"; import * as sio from "socket.io"; import { writeFileSync } from "fs"; import { Game } from "./utils/Game"; import { Vote } from "./events/Vote"; import { LOG_NAME } from "./constants"; import { KillGame } from "./events/KillGame"; import { JoinGame } from "./events/JoinGame"; import { HostGame } from "./events/HostGame"; import { StartGame } from "./events/StartGame"; import { VetoConfirm } from "./events/VetoConfirm"; import { VetoRequest } from "./events/VetoRequest"; import { RemovePlayer } from "./events/RemovePlayer"; import { ExecutePlayer } from "./events/ExecutePlayer"; import { GetPlayerList } from "./events/GetPlayerList"; import { NextPresident } from "./events/NextPresident"; import { InvestigateParty } from "./events/InvestigateParty"; import { ChancellorPolicy } from "./events/ChancellorPolicy"; import { PresidentPolicies } from "./events/PresidentPolicies"; import { ChancellorNomination } from "./events/ChancellorNomination"; import { ExecutiveConfirmation } from "./events/ExecutiveConfirmation"; // Argument parsing const args = arg({ "--port": Number, "--log": String, // Aliases "-l": "--log", "-p": "--port", "--level": "--log" }); const LOG_LEVEL: log_level = args["--log"] as log_level || `info`; const WSS_PORT = args["--port"] || 3000; // Ensure the log level is valid if (![`silly`,`debug`,`info`,`error`,`warn`,`fatal`,`trace`].includes(LOG_LEVEL)) { throw new Error(`Invalid log level: ${LOG_LEVEL}`) } export var log: Logger = new Logger({ displayFunctionName: false, displayLoggerName: false, displayFilePath: `hidden`, displayLogLevel: true, minLevel: LOG_LEVEL, name: LOG_NAME, }); export var active_games: {[key: string]: Game} = {}; const db_dir = `data`; /** * This function is called whenever the main node process is terminated for * whatever reason. It cleans up and writes all the active games to the disk. */ function clean_up() { log.info(`Cleaning up games...`); for (var code in active_games) { log.debug(`Writing game: ${code} to disk`); log.silly(active_games[code].toString()); // writeFileSync(`${db_dir}/${code}`, active_games[code].toJSON()); }; log.info(`Finished cleanup. Exiting.`); process.exit(0); }; // Listen to the signals for the cleanup requirement process.on(`uncaughtException`, clean_up); process.on('SIGINT', clean_up); const io = sio.listen(WSS_PORT); io.on(`connection`, (socket: sio.Socket) => { log.info(`Client connected with id ${socket.id}`); // Game Management socket.on(`HostGame`, (data: HostGame) => HostGame(io, socket, data)); socket.on(`JoinGame`, (data: JoinGame) => JoinGame(io, socket, data)); socket.on(`KillGame`, (data: KillGame) => KillGame(io, socket, data)); socket.on(`RemovePlayer`, (data: RemovePlayer) => RemovePlayer(io, socket, data)); // Join a game socket.on(`StartGame`, (data: any) => StartGame(io, socket, data)); // Chancellor Nominations socket.on(`ChancellorNomination`, (data: any) => ChancellorNomination(io, socket, data)); socket.on(`Vote`, Vote); // Policy Receiving socket.on(`PresidentPolicies`, (data: any) => PresidentPolicies(io, socket, data)); socket.on(`ChancellorPolicy`, (data: any) => ChancellorPolicy(io, socket, data)); socket.on(`VetoRequest`, (data: any) => VetoRequest(io, socket, data)); socket.on(`VetoConfirm`, (data: any) => VetoConfirm(io, socket, data)); // Special Actions socket.on(`ExecutePlayer`, (data: any) => ExecutePlayer(io, socket, data)); socket.on(`NextPresident`, (data: any) => NextPresident(io, socket, data)); socket.on(`ExecutiveConfirmation`, (data: any) => ExecutiveConfirmation(io, socket, data)); socket.on(`InvestigateParty`, (data: any) => InvestigateParty(io, socket, data)); // Utility Events socket.on(`GetPlayerList`, (data: GetPlayerList) => GetPlayerList(io, socket, data)); }); io.on(`reconnect_attempt`, (socket: sio.Socket) => { log.info(`Client attempting to reconnect`) }); io.on(`disconnect`, (socket: sio.Socket) => { log.info(`Client disconnected`) }); log.info(`Server started on port ${WSS_PORT}`);