persist games in fixed intervals and on shutdown

This commit is contained in:
Zutatensuppe 2020-12-04 00:04:47 +01:00
parent 5160008c89
commit 996822b046
5 changed files with 88 additions and 36 deletions

View file

@ -7,6 +7,19 @@ export const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1
// get one random item from the given array // get one random item from the given array
export const choice = (array) => array[randomInt(0, array.length - 1)] 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 // return a shuffled (shallow) copy of the given array
export const shuffle = (array) => { export const shuffle = (array) => {
let arr = array.slice() let arr = array.slice()
@ -37,6 +50,7 @@ export default {
uniqId, uniqId,
randomInt, randomInt,
choice, choice,
throttle,
shuffle, shuffle,
timestamp, timestamp,
} }

View file

@ -2,4 +2,4 @@
cd "$RUN_DIR/server" cd "$RUN_DIR/server"
nodemon -d 2 index.js nodemon index.js

View file

@ -30,18 +30,21 @@ function loadAllGames() {
} }
} }
function store(gameId) { function persistAll() {
const game = GameCommon.get(gameId) const games = GameCommon.getAllGames()
fs.writeFileSync('./../data/' + gameId + '.json', JSON.stringify({ for (const gameId of Object.keys(games)) {
puzzle: game.puzzle, const game = games[gameId]
players: game.players, fs.writeFileSync('./../data/' + gameId + '.json', JSON.stringify({
})) puzzle: game.puzzle,
players: game.players,
}))
}
} }
export default { export default {
loadAllGames, loadAllGames,
getAllGames: GameCommon.getAllGames, getAllGames: GameCommon.getAllGames,
store, persistAll,
createGame, createGame,
exists: GameCommon.exists, exists: GameCommon.exists,
addPlayer: GameCommon.addPlayer, addPlayer: GameCommon.addPlayer,

View file

@ -61,6 +61,10 @@ class WebSocketServer {
}) })
} }
close() {
this._websocketserver.close()
}
notifyOne(data, socket) { notifyOne(data, socket) {
socket.send(JSON.stringify(data)) socket.send(JSON.stringify(data))
} }

View file

@ -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}) => { wss.on('message', async ({socket, data}) => {
try { try {
const proto = socket.protocol.split('|') const proto = socket.protocol.split('|')
@ -145,14 +121,39 @@ wss.on('message', async ({socket, data}) => {
if (!Game.exists(gameId)) { if (!Game.exists(gameId)) {
throw `[game ${gameId} does not exist... ]` 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; } break;
case Protocol.EV_CLIENT_EVENT: { case Protocol.EV_CLIENT_EVENT: {
const clientSeq = msg[1] const clientSeq = msg[1]
const clientEvtData = msg[2] const clientEvtData = msg[2]
ensurePlayerGame(gameId, clientId, socket) Game.addPlayer(gameId, clientId)
handlePlayerInput(gameId, clientId, clientSeq, clientEvtData) 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; } break;
} }
} catch (e) { } catch (e) {
@ -161,5 +162,35 @@ wss.on('message', async ({socket, data}) => {
}) })
Game.loadAllGames() 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() 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')
});