From 996822b04634f75690d6f5874355026b69701a87 Mon Sep 17 00:00:00 2001 From: Zutatensuppe Date: Fri, 4 Dec 2020 00:04:47 +0100 Subject: [PATCH] persist games in fixed intervals and on shutdown --- common/Util.js | 14 +++++++ scripts/server | 2 +- server/Game.js | 17 ++++---- server/WebSocketServer.js | 4 ++ server/index.js | 87 ++++++++++++++++++++++++++------------- 5 files changed, 88 insertions(+), 36 deletions(-) diff --git a/common/Util.js b/common/Util.js index 1ed3bd4..5980f4c 100644 --- a/common/Util.js +++ b/common/Util.js @@ -7,6 +7,19 @@ export const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1 // get one random item from the given array export const choice = (array) => array[randomInt(0, array.length - 1)] +export const throttle = (fn, delay) => { + let canCall = true + return (...args) => { + if (canCall) { + fn.apply(null, args) + canCall = false + setTimeout(() => { + canCall = true + }, delay) + } + } +} + // return a shuffled (shallow) copy of the given array export const shuffle = (array) => { let arr = array.slice() @@ -37,6 +50,7 @@ export default { uniqId, randomInt, choice, + throttle, shuffle, timestamp, } diff --git a/scripts/server b/scripts/server index 5b5dbf4..3bff09c 100755 --- a/scripts/server +++ b/scripts/server @@ -2,4 +2,4 @@ cd "$RUN_DIR/server" -nodemon -d 2 index.js +nodemon index.js diff --git a/server/Game.js b/server/Game.js index 3256b3f..8d14e87 100644 --- a/server/Game.js +++ b/server/Game.js @@ -30,18 +30,21 @@ function loadAllGames() { } } -function store(gameId) { - const game = GameCommon.get(gameId) - fs.writeFileSync('./../data/' + gameId + '.json', JSON.stringify({ - puzzle: game.puzzle, - players: game.players, - })) +function persistAll() { + const games = GameCommon.getAllGames() + for (const gameId of Object.keys(games)) { + const game = games[gameId] + fs.writeFileSync('./../data/' + gameId + '.json', JSON.stringify({ + puzzle: game.puzzle, + players: game.players, + })) + } } export default { loadAllGames, getAllGames: GameCommon.getAllGames, - store, + persistAll, createGame, exists: GameCommon.exists, addPlayer: GameCommon.addPlayer, diff --git a/server/WebSocketServer.js b/server/WebSocketServer.js index 96d93d9..68fbe0e 100644 --- a/server/WebSocketServer.js +++ b/server/WebSocketServer.js @@ -61,6 +61,10 @@ class WebSocketServer { }) } + close() { + this._websocketserver.close() + } + notifyOne(data, socket) { socket.send(JSON.stringify(data)) } diff --git a/server/index.js b/server/index.js index 9be1bfe..acca305 100644 --- a/server/index.js +++ b/server/index.js @@ -109,30 +109,6 @@ wss.on('close', async ({socket}) => { } }) -const ensurePlayerGame = (gameId, clientId, socket) => { - Game.addPlayer(gameId, clientId) - Game.addSocket(gameId, socket) - Game.store(gameId) - const game = Game.get(gameId) - notify( - [Protocol.EV_SERVER_INIT, { - puzzle: game.puzzle, - players: game.players, - evtInfos: game.evtInfos, - }], - [socket] - ) -} - -const handlePlayerInput = (gameId, clientId, clientSeq, clientEvtData) => { - const changes = Game.handleInput(gameId, clientId, clientEvtData) - Game.store(gameId) - notify( - [Protocol.EV_SERVER_EVENT, clientId, clientSeq, changes], - Game.getSockets(gameId) - ) -} - wss.on('message', async ({socket, data}) => { try { const proto = socket.protocol.split('|') @@ -145,14 +121,39 @@ wss.on('message', async ({socket, data}) => { if (!Game.exists(gameId)) { throw `[game ${gameId} does not exist... ]` } - ensurePlayerGame(gameId, clientId, socket) + Game.addPlayer(gameId, clientId) + Game.addSocket(gameId, socket) + const game = Game.get(gameId) + notify( + [Protocol.EV_SERVER_INIT, { + puzzle: game.puzzle, + players: game.players, + evtInfos: game.evtInfos, + }], + [socket] + ) } break; case Protocol.EV_CLIENT_EVENT: { const clientSeq = msg[1] const clientEvtData = msg[2] - ensurePlayerGame(gameId, clientId, socket) - handlePlayerInput(gameId, clientId, clientSeq, clientEvtData) + Game.addPlayer(gameId, clientId) + Game.addSocket(gameId, socket) + + const game = Game.get(gameId) + notify( + [Protocol.EV_SERVER_INIT, { + puzzle: game.puzzle, + players: game.players, + evtInfos: game.evtInfos, + }], + [socket] + ) + const changes = Game.handleInput(gameId, clientId, clientEvtData) + notify( + [Protocol.EV_SERVER_EVENT, clientId, clientSeq, changes], + Game.getSockets(gameId) + ) } break; } } catch (e) { @@ -161,5 +162,35 @@ wss.on('message', async ({socket, data}) => { }) Game.loadAllGames() -app.listen(port, hostname, () => console.log(`server running on http://${hostname}:${port}`)) +const server = app.listen( + port, + hostname, + () => console.log(`server running on http://${hostname}:${port}`) +) wss.listen() + +// persist games in fixed interval +setInterval(() => { + console.log('Persisting games...'); + Game.persistAll() +}, config.persistence.interval) + +const gracefulShutdown = (signal) => { + console.log(`${signal} received...`) + Game.persistAll() + server.close() + wss.close() +} + +// used by nodemon +process.once('SIGUSR2', function () { + gracefulShutdown('SIGUSR2') +}); + +process.once('SIGINT', function (code) { + gracefulShutdown('SIGINT') +}); + +process.once('SIGTERM', function (code) { + gracefulShutdown('SIGTERM') +});