persist games in fixed intervals and on shutdown
This commit is contained in:
parent
5160008c89
commit
996822b046
5 changed files with 88 additions and 36 deletions
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
cd "$RUN_DIR/server"
|
cd "$RUN_DIR/server"
|
||||||
|
|
||||||
nodemon -d 2 index.js
|
nodemon index.js
|
||||||
|
|
|
||||||
|
|
@ -30,18 +30,21 @@ function loadAllGames() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function store(gameId) {
|
function persistAll() {
|
||||||
const game = GameCommon.get(gameId)
|
const games = GameCommon.getAllGames()
|
||||||
|
for (const gameId of Object.keys(games)) {
|
||||||
|
const game = games[gameId]
|
||||||
fs.writeFileSync('./../data/' + gameId + '.json', JSON.stringify({
|
fs.writeFileSync('./../data/' + gameId + '.json', JSON.stringify({
|
||||||
puzzle: game.puzzle,
|
puzzle: game.puzzle,
|
||||||
players: game.players,
|
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,
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue