mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 07:47:50 +01:00
gcloud config, various bugfixes
This commit is contained in:
20
app.yaml
20
app.yaml
@@ -1,5 +1,19 @@
|
||||
runtime: nodejs
|
||||
env: flex
|
||||
entrypoint: npm run start:prod:linux
|
||||
automatic_scaling:
|
||||
max_instances: 1
|
||||
network:
|
||||
session_affinity: true
|
||||
liveness_check:
|
||||
path: "/liveness_check"
|
||||
check_interval_sec: 60
|
||||
timeout_sec: 4
|
||||
failure_threshold: 2
|
||||
success_threshold: 2
|
||||
readiness_check:
|
||||
path: "/readiness_check"
|
||||
check_interval_sec: 60
|
||||
timeout_sec: 4
|
||||
failure_threshold: 2
|
||||
success_threshold: 2
|
||||
app_start_timeout_sec: 600
|
||||
manual_scaling:
|
||||
instances: 1
|
||||
|
||||
BIN
client/src/images/GitHub-Mark-Light-120px-plus.png
Normal file
BIN
client/src/images/GitHub-Mark-Light-120px-plus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,7 +1,7 @@
|
||||
export class DeckStateManager {
|
||||
constructor() {
|
||||
this.deck = null;
|
||||
this.customRoleOptions = null;
|
||||
this.customRoleOptions = [];
|
||||
}
|
||||
|
||||
addToDeck(role) {
|
||||
|
||||
@@ -67,7 +67,6 @@ export class GameCreationStepManager {
|
||||
this.currentGame.hasTimer = false;
|
||||
this.currentGame.timerParams = null;
|
||||
}
|
||||
console.log(this.currentGame);
|
||||
cancelCurrentToast();
|
||||
this.removeStepElementsFromDOM(this.step);
|
||||
this.incrementStep();
|
||||
@@ -102,6 +101,10 @@ export class GameCreationStepManager {
|
||||
) {
|
||||
window.location = ('/game/' + res.content);
|
||||
}
|
||||
}).catch((e) => {
|
||||
if (e.status === 429) {
|
||||
toast('You\'ve sent this request too many times.', 'error', true, true, 6);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -450,8 +453,9 @@ function initializeRemainingEventListeners(deckManager) {
|
||||
e.preventDefault();
|
||||
let name = document.getElementById("role-name").value.trim();
|
||||
let description = document.getElementById("role-description").value.trim();
|
||||
let team = document.getElementById("role-alignment").value.toLowerCase().trim();
|
||||
if (!deckManager.getCustomRoleOption(name)) { // confirm there is no existing custom role with the same name
|
||||
deckManager.addToCustomRoleOptions({role: name, description: description});
|
||||
deckManager.addToCustomRoleOptions({role: name, description: description, team: team});
|
||||
updateCustomRoleOptionsList(deckManager, document.getElementById("deck-select"))
|
||||
ModalManager.dispelModal("add-role-modal", "add-role-modal-background");
|
||||
toast("Role Added", "success", true);
|
||||
@@ -481,10 +485,10 @@ function addOptionsToList(options, selectEl) {
|
||||
});
|
||||
for (let i = 0; i < options.length; i ++) {
|
||||
let optionEl = document.createElement("option");
|
||||
let alignmentClass = customCards[i].team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL
|
||||
let alignmentClass = options[i].team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL
|
||||
optionEl.classList.add(alignmentClass);
|
||||
optionEl.setAttribute("value", customCards[i].role);
|
||||
optionEl.innerText = customCards[i].role;
|
||||
optionEl.setAttribute("value", options[i].role);
|
||||
optionEl.innerText = options[i].role;
|
||||
selectEl.appendChild(optionEl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ export class GameStateRenderer {
|
||||
title.innerText = "Lobby";
|
||||
document.getElementById("game-title").appendChild(title);
|
||||
let gameLinkContainer = document.getElementById("game-link");
|
||||
gameLinkContainer.innerText = window.location;
|
||||
let linkDiv = document.createElement("div");
|
||||
linkDiv.innerText = window.location;
|
||||
gameLinkContainer.prepend(linkDiv);
|
||||
gameLinkContainer.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(gameLinkContainer.innerText).then(() => {
|
||||
toast('Link copied!', 'success', true);
|
||||
@@ -265,7 +267,6 @@ function renderPotentialMods(gameState, group, transferModHandlers, socket) {
|
||||
|
||||
container.addEventListener('click', transferModHandlers[member.id]);
|
||||
modalContent.appendChild(container);
|
||||
console.log('test');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,6 @@ export class GameTimerManager {
|
||||
|
||||
if(!socket.hasListeners(globals.COMMANDS.GET_TIME_REMAINING)) {
|
||||
socket.on(globals.COMMANDS.GET_TIME_REMAINING, (timeRemaining, paused) => {
|
||||
console.log('received time remaining from server');
|
||||
if (paused) {
|
||||
this.displayPausedTime(timeRemaining);
|
||||
} else if (timeRemaining === 0) {
|
||||
@@ -151,6 +150,16 @@ export class GameTimerManager {
|
||||
pauseBtn.addEventListener('click', this.pauseListener);
|
||||
document.getElementById('play-pause').appendChild(pauseBtn);
|
||||
}
|
||||
|
||||
processTimeRemaining(timeRemaining, paused, timerWorker) {
|
||||
if (paused) {
|
||||
this.displayPausedTime(timeRemaining);
|
||||
} else if (timeRemaining === 0) {
|
||||
this.displayExpiredTime();
|
||||
} else {
|
||||
this.resumeGameTimer(timeRemaining, globals.CLOCK_TICK_INTERVAL_MILLIS, null, timerWorker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function returnHumanReadableTime(milliseconds, tenthsOfSeconds=false) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* It started getting confusing where I am reading/writing to the game state, and thus the state started to get inconsistent.
|
||||
Creating a bucket to hold it so I can overwrite the gameState object whilst still preserving a reference to the containing bucket.
|
||||
Now several components can read a shared game state.
|
||||
*/
|
||||
export const stateBucket = {
|
||||
currentGameState: null,
|
||||
|
||||
@@ -128,6 +128,9 @@ export const templates = {
|
||||
"</div>" +
|
||||
"<div id='play-pause'>" + "</div>" +
|
||||
"</div>" +
|
||||
"<div>" +
|
||||
"<button id='role-info-button'>View Role Info <img src='/images/info.svg'</button>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div id='game-role' style='display:none'>" +
|
||||
"<h4 id='role-name'></h4>" +
|
||||
|
||||
@@ -7,7 +7,7 @@ const create = () => {
|
||||
let deckManager = new DeckStateManager();
|
||||
let gameCreationStepManager = new GameCreationStepManager(deckManager);
|
||||
loadDefaultCards(deckManager);
|
||||
loadCustomRoles(deckManager);
|
||||
//loadCustomRoles(deckManager);
|
||||
gameCreationStepManager.renderStep("creation-step-container", 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ function prepareGamePage(environment, socket, timerWorker) {
|
||||
|
||||
document.getElementById("game-content").innerHTML = templates.INITIAL_GAME_DOM;
|
||||
toast('You are connected.', 'success', true, true, 2);
|
||||
console.log(gameState);
|
||||
userId = gameState.client.cookie;
|
||||
UserUtility.setAnonymousUserId(userId, environment);
|
||||
let gameStateRenderer = new GameStateRenderer(stateBucket, socket);
|
||||
@@ -66,7 +65,7 @@ function prepareGamePage(environment, socket, timerWorker) {
|
||||
ModalManager.dispelModal("change-name-modal", "change-name-modal-background")
|
||||
toast('Name set.', 'success', true, true, 5);
|
||||
propagateNameChange(stateBucket.currentGameState, name, stateBucket.currentGameState.client.id);
|
||||
processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer);
|
||||
processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -82,10 +81,10 @@ function prepareGamePage(environment, socket, timerWorker) {
|
||||
|
||||
function initializeGame(stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager) {
|
||||
setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager);
|
||||
processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer);
|
||||
processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker);
|
||||
}
|
||||
|
||||
function processGameState (currentGameState, userId, socket, gameStateRenderer) {
|
||||
function processGameState (currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker) {
|
||||
displayClientInfo(currentGameState.client.name, currentGameState.client.userType);
|
||||
switch (currentGameState.status) {
|
||||
case globals.STATUS.LOBBY:
|
||||
@@ -133,7 +132,9 @@ function processGameState (currentGameState, userId, socket, gameStateRenderer)
|
||||
break;
|
||||
}
|
||||
if (currentGameState.timerParams) {
|
||||
socket.emit(globals.COMMANDS.GET_TIME_REMAINING, currentGameState.accessCode);
|
||||
socket.emit(globals.COMMANDS.GET_TIME_REMAINING, currentGameState.accessCode, (timeRemaining, paused) => {
|
||||
gameTimerManager.processTimeRemaining(timeRemaining, paused, timerWorker);
|
||||
});
|
||||
} else {
|
||||
document.querySelector('#game-timer')?.remove();
|
||||
document.querySelector('label[for="game-timer"]')?.remove();
|
||||
@@ -183,7 +184,7 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo
|
||||
stateBucket.currentGameState.client.cookie,
|
||||
function (gameState) {
|
||||
stateBucket.currentGameState = gameState;
|
||||
processGameState(stateBucket.currentGameState, gameState.client.cookie, socket, gameStateRenderer);
|
||||
processGameState(stateBucket.currentGameState, gameState.client.cookie, socket, gameStateRenderer, gameTimerManager, timerWorker);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -252,7 +253,7 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo
|
||||
socket.on(globals.EVENTS.CHANGE_NAME, (personId, name) => {
|
||||
propagateNameChange(stateBucket.currentGameState, name, personId);
|
||||
updateDOMWithNameChange(stateBucket.currentGameState, gameStateRenderer);
|
||||
processGameState(stateBucket.currentGameState, stateBucket.currentGameState.client.cookie, socket, gameStateRenderer);
|
||||
processGameState(stateBucket.currentGameState, stateBucket.currentGameState.client.cookie, socket, gameStateRenderer, gameTimerManager, timerWorker);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -260,7 +261,7 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo
|
||||
socket.on(globals.COMMANDS.END_GAME, (people) => {
|
||||
stateBucket.currentGameState.people = people;
|
||||
stateBucket.currentGameState.status = globals.STATUS.ENDED;
|
||||
processGameState(stateBucket.currentGameState, stateBucket.currentGameState.client.cookie, socket, gameStateRenderer);
|
||||
processGameState(stateBucket.currentGameState, stateBucket.currentGameState.client.cookie, socket, gameStateRenderer, gameTimerManager, timerWorker);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,19 @@ body {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bmc-btn {
|
||||
height: 40px !important;
|
||||
border-radius: 3px !important;
|
||||
font-size: 18px !important;
|
||||
min-width: 180px !important;
|
||||
padding: 0 17px !important;
|
||||
}
|
||||
|
||||
.bmc-btn-text {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@@ -76,6 +89,7 @@ h3 {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
font-family: 'diavlo', sans-serif;
|
||||
margin: 0 0.25em;
|
||||
}
|
||||
|
||||
#footer a:hover {
|
||||
|
||||
@@ -257,6 +257,7 @@ input[type="number"] {
|
||||
#game-creation-container {
|
||||
width: 95%;
|
||||
max-width: 60em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#tracker-container {
|
||||
|
||||
@@ -58,6 +58,7 @@ body {
|
||||
|
||||
#lobby-header {
|
||||
margin-bottom: 1em;
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@@ -115,13 +116,6 @@ h1 {
|
||||
}
|
||||
|
||||
#game-link {
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
padding: 7px;
|
||||
@@ -134,6 +128,13 @@ h1 {
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
#game-link > div {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.role-info-name {
|
||||
display: flex;
|
||||
}
|
||||
@@ -277,6 +278,9 @@ h1 {
|
||||
font-size: 35px;
|
||||
text-shadow: 0 3px 4px rgb(0 0 0 / 85%);
|
||||
border: 1px solid #747474;
|
||||
min-width: 5em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#game-timer.low {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.modal {
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
width: 85%;
|
||||
z-index: 100;
|
||||
top: 50%;
|
||||
@@ -11,7 +11,6 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-width: 25em;
|
||||
height: fit-content;
|
||||
font-family: sans-serif;
|
||||
flex-direction: column;
|
||||
padding: 1em;
|
||||
@@ -49,3 +48,11 @@
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#change-name-modal, #transfer-mod-modal, #role-info-modal {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#role-info-modal, #transfer-mod-modal {
|
||||
max-height: 80%;
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@
|
||||
</div>
|
||||
<footer id="footer" class="game-page-footer">
|
||||
<div>
|
||||
<a href="https://github.com/AlecM33/Werewolf"><img src='/images/GitHub-Mark-Light-32px.png'/></a>
|
||||
<a href="mailto:leohfx@gmail.com?Subject=Werewolf App Question" target="_top"><img src='/images/email.svg'/></a>
|
||||
<a href="https://github.com/AlecM33/Werewolf"><img src='/images/GitHub-Mark-Light-120px-plus.png'/></a>
|
||||
<a href="mailto:play.werewolf.contact@gmail.com?Subject=Werewolf App" target="_top"><img src='/images/email.svg'/></a>
|
||||
</div>
|
||||
<div>
|
||||
<p>Werewolf created by Andrew Plotkin</p>
|
||||
|
||||
@@ -36,13 +36,10 @@
|
||||
</form>
|
||||
</div>
|
||||
<footer id="footer">
|
||||
<a class="bmc-button" target="_blank" href="https://www.buymeacoffee.com/alecm33">
|
||||
<span alt="Buy me a beer">🍺</span>
|
||||
<span style="margin-left:5px;">Buy me a beer</span>
|
||||
</a>
|
||||
<script type="text/javascript" src="https://cdnjs.buymeacoffee.com/1.0.0/button.prod.min.js" data-name="bmc-button" data-slug="alecm33" data-color="#333243" data-emoji="" data-font="Lato" data-text="Buy me a coffee" data-outline-color="#ffffff" data-font-color="#ffffff" data-coffee-color="#FFDD00" ></script>
|
||||
<div>
|
||||
<a href="https://github.com/AlecM33/Werewolf"><img src='/images/GitHub-Mark-Light-32px.png'/></a>
|
||||
<a href="mailto:leohfx@gmail.com?Subject=Werewolf App Question" target="_top"><img src='/images/email.svg'/></a>
|
||||
<a href="https://github.com/AlecM33/Werewolf"><img src='/images/GitHub-Mark-Light-120px-plus.png'/></a>
|
||||
<a href="mailto:play.werewolf.contact@gmail.com?Subject=Werewolf App" target="_top"><img src='/images/email.svg'/></a>
|
||||
</div>
|
||||
<div>
|
||||
<p>Werewolf created by Andrew Plotkin</p>
|
||||
|
||||
@@ -12,6 +12,7 @@ module.exports = {
|
||||
},
|
||||
mode: "development",
|
||||
node: false,
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const path = require('path');
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
@@ -12,7 +13,6 @@ module.exports = {
|
||||
},
|
||||
mode: "production",
|
||||
node: false,
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
||||
919
package-lock.json
generated
919
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -15,25 +15,26 @@
|
||||
"test:unit": "jasmine",
|
||||
"test:e2e": "node browsertest.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"express-force-https": "^1.0.0",
|
||||
"jasmine": "^3.5.0",
|
||||
"socket.io": "^4.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
"@babel/plugin-transform-object-assign": "^7.16.5",
|
||||
"@babel/preset-env": "^7.16.5",
|
||||
"acorn": "^8.6.0",
|
||||
"babel-loader": "^8.2.3",
|
||||
"css-loader": "^6.5.1",
|
||||
"express": "^4.17.1",
|
||||
"express-force-https": "^1.0.0",
|
||||
"express-rate-limit": "^6.0.1",
|
||||
"open": "^7.0.3",
|
||||
"socket.io": "^4.4.0",
|
||||
"socket.io-client": "^4.4.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-remove-debug": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,21 @@ const router = express.Router();
|
||||
const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())).includes('debug');
|
||||
const logger = require('../modules/Logger')(debugMode);
|
||||
const GameManager = require('../modules/GameManager.js');
|
||||
const rateLimit = require('express-rate-limit').default
|
||||
|
||||
const gameManager = new GameManager().getInstance();
|
||||
|
||||
const apiLimiter = rateLimit({
|
||||
windowMs: 600000,
|
||||
max: 3,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV.trim() === 'production') { // in prod, limit clients to creating 3 games per 10 minutes.
|
||||
router.use('/create', apiLimiter);
|
||||
}
|
||||
|
||||
router.post('/create', function (req, res) {
|
||||
logger.debug('Received request to create new game: ' + JSON.stringify(req.body, null, 4));
|
||||
const gameCreationPromise = gameManager.createGame(req.body, false);
|
||||
|
||||
@@ -2,6 +2,7 @@ const globals = {
|
||||
ACCESS_CODE_CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789',
|
||||
ACCESS_CODE_LENGTH: 6,
|
||||
CLOCK_TICK_INTERVAL_MILLIS: 10,
|
||||
STALE_GAME_HOURS: 12,
|
||||
CLIENT_COMMANDS: {
|
||||
FETCH_GAME_STATE: 'fetchGameState',
|
||||
GET_ENVIRONMENT: 'getEnvironment',
|
||||
@@ -50,7 +51,7 @@ const globals = {
|
||||
TRACE: "trace"
|
||||
},
|
||||
GAME_PROCESS_COMMANDS: {
|
||||
END_GAME: "endGame",
|
||||
END_TIMER: "endTimer",
|
||||
START_GAME: "startGame",
|
||||
START_TIMER: "startTimer",
|
||||
PAUSE_TIMER: "pauseTimer",
|
||||
|
||||
@@ -3,7 +3,6 @@ const http = require('http');
|
||||
const https = require('https');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const socketIO = require('socket.io');
|
||||
const app = express();
|
||||
const bodyParser = require('body-parser');
|
||||
const GameManager = require('./modules/GameManager.js');
|
||||
@@ -62,10 +61,31 @@ if (localServer) {
|
||||
app.use(secure);
|
||||
}
|
||||
|
||||
const io = socketIO(main);
|
||||
|
||||
app.set('port', port);
|
||||
|
||||
let io;
|
||||
|
||||
if (process.env.NODE_ENV.trim() === 'development') {
|
||||
io = require("socket.io")(main, {
|
||||
cors: {
|
||||
origin: "http://localhost:" + port,
|
||||
methods: ["GET", "POST"],
|
||||
allowedHeaders: ["Content-Type", "X-Requested-With", "Accept"],
|
||||
credentials: false
|
||||
}
|
||||
});
|
||||
} else {
|
||||
io = require("socket.io")(main, {
|
||||
cors: {
|
||||
origin: ["https://playwerewolf.uk.r.appspot.com", "wss://playwerewolf.uk.r.appspot.com"],
|
||||
methods: ["GET", "POST"],
|
||||
allowedHeaders: ["Content-Type", "X-Requested-With", "Accept"],
|
||||
credentials: false
|
||||
},
|
||||
transports: ["polling"]
|
||||
});
|
||||
}
|
||||
|
||||
const inGame = io.of('/in-game');
|
||||
|
||||
|
||||
@@ -76,7 +96,6 @@ const gameManager = new GameManager(logger, globals.ENVIRONMENT.LOCAL).getInstan
|
||||
/* Instantiate the singleton queue manager */
|
||||
//const queueManager = new QueueManager(matchmaking, logger).getInstance();
|
||||
|
||||
|
||||
/* api endpoints */
|
||||
const games = require('./api/GamesAPI');
|
||||
app.use('/api/games', games);
|
||||
|
||||
@@ -18,12 +18,10 @@ class ActiveGameRunner {
|
||||
this.timerThreads[game.accessCode] = gameProcess;
|
||||
gameProcess.on('message', (msg) => {
|
||||
switch (msg.command) {
|
||||
case globals.GAME_PROCESS_COMMANDS.END_GAME:
|
||||
//game.status = globals.STATUS.ENDED;
|
||||
case globals.GAME_PROCESS_COMMANDS.END_TIMER:
|
||||
game.timerParams.paused = false;
|
||||
game.timerParams.timeRemaining = 0;
|
||||
this.logger.trace('PARENT: END GAME');
|
||||
namespace.in(game.accessCode).emit(globals.GAME_PROCESS_COMMANDS.END_GAME, game.accessCode);
|
||||
this.logger.trace('PARENT: END TIMER');
|
||||
break;
|
||||
case globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER:
|
||||
game.timerParams.paused = true;
|
||||
|
||||
@@ -178,6 +178,8 @@ class GameManager {
|
||||
this.logger.error('Tried to create game with invalid options: ' + JSON.stringify(gameParams));
|
||||
return Promise.reject('Tried to create game with invalid options: ' + gameParams);
|
||||
} else {
|
||||
// to avoid excessive memory build-up, every time a game is created, check for and purge any stale games.
|
||||
pruneStaleGames(this.activeGameRunner.activeGames, this.activeGameRunner.timerThreads, this.logger);
|
||||
const newAccessCode = this.generateAccessCode();
|
||||
let moderator = initializeModerator(UsernameGenerator.generate(), gameParams.hasDedicatedModerator);
|
||||
if (gameParams.timerParams !== null) {
|
||||
@@ -192,6 +194,7 @@ class GameManager {
|
||||
moderator,
|
||||
gameParams.timerParams
|
||||
);
|
||||
this.activeGameRunner.activeGames[newAccessCode].createTime = new Date().toJSON();
|
||||
return Promise.resolve(newAccessCode);
|
||||
}
|
||||
}
|
||||
@@ -359,12 +362,11 @@ function handleRequestForGameState(namespace, logger, gameRunner, accessCode, pe
|
||||
logger.trace('this person is already associated with a socket connection');
|
||||
let alreadyConnectedSocket = namespace.connected[matchingPerson.socketId];
|
||||
if (alreadyConnectedSocket && alreadyConnectedSocket.leave) {
|
||||
alreadyConnectedSocket.leave(accessCode, ()=> {
|
||||
logger.trace('kicked existing connection out of room ' + accessCode);
|
||||
socket.join(accessCode);
|
||||
matchingPerson.socketId = socket.id;
|
||||
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson, gameRunner, socket, logger));
|
||||
})
|
||||
alreadyConnectedSocket.leave(accessCode);
|
||||
logger.trace('kicked existing connection out of room ' + accessCode);
|
||||
socket.join(accessCode);
|
||||
matchingPerson.socketId = socket.id;
|
||||
ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson, gameRunner, socket, logger));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,7 +400,7 @@ function handleRequestForGameState(namespace, logger, gameRunner, accessCode, pe
|
||||
}
|
||||
} else {
|
||||
rejectClientRequestForGameState(ackFn);
|
||||
logger.trace('the game' + accessCode + ' was not found');
|
||||
logger.trace('the game ' + accessCode + ' was not found');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,4 +444,21 @@ function isNameTaken(game, name) {
|
||||
|| (game.spectators.find((spectator) => spectator.name.toLowerCase().trim() === processedName))
|
||||
}
|
||||
|
||||
function pruneStaleGames(activeGames, timerThreads, logger) {
|
||||
for (const [accessCode, game] of Object.entries(activeGames)) {
|
||||
if (game.createTime) {
|
||||
let createDate = new Date(game.createTime);
|
||||
if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) { // clear games created more than 12 hours ago
|
||||
logger.info('PRUNING STALE GAME ' + accessCode);
|
||||
delete activeGames[accessCode];
|
||||
if (timerThreads[accessCode]) {
|
||||
logger.info('KILLING STALE TIMER PROCESS FOR ' + accessCode);
|
||||
timerThreads[accessCode].kill();
|
||||
delete timerThreads[accessCode];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Singleton;
|
||||
|
||||
@@ -16,7 +16,7 @@ process.on('message', (msg) => {
|
||||
);
|
||||
timer.runTimer().then(() => {
|
||||
logger.debug('Timer finished for ' + msg.accessCode);
|
||||
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_GAME });
|
||||
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_TIMER });
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ process.on('message', (msg) => {
|
||||
case globals.GAME_PROCESS_COMMANDS.RESUME_TIMER:
|
||||
timer.resumeTimer().then(() => {
|
||||
logger.debug('Timer finished for ' + msg.accessCode);
|
||||
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_GAME });
|
||||
process.send({ command: globals.GAME_PROCESS_COMMANDS.END_TIMER });
|
||||
process.exit(0);
|
||||
});
|
||||
logger.trace('CHILD PROCESS ' + msg.accessCode + ': RESUME TIMER');
|
||||
|
||||
@@ -14,5 +14,13 @@ router.get('/game/:code', function (request, response) {
|
||||
response.sendFile(path.join(__dirname, '../../client/src/views/game.html'));
|
||||
});
|
||||
|
||||
router.get('/liveness_check', (req, res) => {
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
router.get('/readiness_check', (req, res) => {
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user