switch to typescript
This commit is contained in:
parent
031ca31c7e
commit
23559b1a3b
63 changed files with 7943 additions and 1397 deletions
269
server/index.js
269
server/index.js
|
|
@ -1,269 +0,0 @@
|
|||
import WebSocketServer from './WebSocketServer.js'
|
||||
|
||||
import express from 'express'
|
||||
import multer from 'multer'
|
||||
import config from './../config.js'
|
||||
import Protocol from './../common/Protocol.js'
|
||||
import Util, { logger } from './../common/Util.js'
|
||||
import Game from './Game.js'
|
||||
import bodyParser from 'body-parser'
|
||||
import v8 from 'v8'
|
||||
import GameLog from './GameLog.js'
|
||||
import GameSockets from './GameSockets.js'
|
||||
import Time from '../common/Time.js'
|
||||
import Images from './Images.js'
|
||||
import {
|
||||
UPLOAD_DIR,
|
||||
UPLOAD_URL,
|
||||
COMMON_DIR,
|
||||
PUBLIC_DIR,
|
||||
} from './Dirs.js'
|
||||
import GameCommon from '../common/GameCommon.js'
|
||||
import GameStorage from './GameStorage.js'
|
||||
|
||||
const log = logger('index.js')
|
||||
|
||||
const port = config.http.port
|
||||
const hostname = config.http.hostname
|
||||
const app = express()
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: UPLOAD_DIR,
|
||||
filename: function (req, file, cb) {
|
||||
cb(null , file.originalname);
|
||||
}
|
||||
})
|
||||
const upload = multer({storage}).single('file');
|
||||
|
||||
app.get('/api/conf', (req, res) => {
|
||||
res.send({
|
||||
WS_ADDRESS: config.ws.connectstring,
|
||||
})
|
||||
})
|
||||
|
||||
app.get('/api/newgame-data', (req, res) => {
|
||||
res.send({
|
||||
images: Images.allImages(),
|
||||
})
|
||||
})
|
||||
|
||||
app.get('/api/index-data', (req, res) => {
|
||||
const ts = Time.timestamp()
|
||||
const games = [
|
||||
...Game.getAllGames().map(game => ({
|
||||
id: game.id,
|
||||
hasReplay: GameLog.exists(game.id),
|
||||
started: Game.getStartTs(game.id),
|
||||
finished: Game.getFinishTs(game.id),
|
||||
tilesFinished: Game.getFinishedTileCount(game.id),
|
||||
tilesTotal: Game.getTileCount(game.id),
|
||||
players: Game.getActivePlayers(game.id, ts).length,
|
||||
imageUrl: Game.getImageUrl(game.id),
|
||||
})),
|
||||
]
|
||||
|
||||
res.send({
|
||||
gamesRunning: games.filter(g => !g.finished),
|
||||
gamesFinished: games.filter(g => !!g.finished),
|
||||
})
|
||||
})
|
||||
|
||||
app.post('/upload', (req, res) => {
|
||||
upload(req, res, async (err) => {
|
||||
if (err) {
|
||||
log.log(err)
|
||||
res.status(400).send("Something went wrong!");
|
||||
}
|
||||
|
||||
try {
|
||||
await Images.resizeImage(req.file.filename)
|
||||
} catch (err) {
|
||||
log.log(err)
|
||||
res.status(400).send("Something went wrong!");
|
||||
}
|
||||
|
||||
res.send({
|
||||
image: {
|
||||
file: `${UPLOAD_DIR}/${req.file.filename}`,
|
||||
url: `${UPLOAD_URL}/${req.file.filename}`,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
app.post('/newgame', bodyParser.json(), async (req, res) => {
|
||||
log.log(req.body.tiles, req.body.image)
|
||||
const gameId = Util.uniqId()
|
||||
if (!Game.exists(gameId)) {
|
||||
const ts = Time.timestamp()
|
||||
await Game.createGame(
|
||||
gameId,
|
||||
req.body.tiles,
|
||||
req.body.image,
|
||||
ts,
|
||||
req.body.scoreMode
|
||||
)
|
||||
}
|
||||
res.send({ id: gameId })
|
||||
})
|
||||
|
||||
app.use('/common/', express.static(COMMON_DIR))
|
||||
app.use('/uploads/', express.static(UPLOAD_DIR))
|
||||
app.use('/', express.static(PUBLIC_DIR))
|
||||
|
||||
const wss = new WebSocketServer(config.ws);
|
||||
|
||||
const notify = (data, sockets) => {
|
||||
// TODO: throttle?
|
||||
for (let socket of sockets) {
|
||||
wss.notifyOne(data, socket)
|
||||
}
|
||||
}
|
||||
|
||||
wss.on('close', async ({socket}) => {
|
||||
try {
|
||||
const proto = socket.protocol.split('|')
|
||||
const clientId = proto[0]
|
||||
const gameId = proto[1]
|
||||
GameSockets.removeSocket(gameId, socket)
|
||||
} catch (e) {
|
||||
log.error(e)
|
||||
}
|
||||
})
|
||||
|
||||
wss.on('message', async ({socket, data}) => {
|
||||
try {
|
||||
const proto = socket.protocol.split('|')
|
||||
const clientId = proto[0]
|
||||
const gameId = proto[1]
|
||||
const msg = JSON.parse(data)
|
||||
const msgType = msg[0]
|
||||
switch (msgType) {
|
||||
case Protocol.EV_CLIENT_INIT_REPLAY: {
|
||||
if (!GameLog.exists(gameId)) {
|
||||
throw `[gamelog ${gameId} does not exist... ]`
|
||||
}
|
||||
const log = GameLog.get(gameId)
|
||||
const game = await Game.createGameObject(
|
||||
gameId,
|
||||
log[0][2],
|
||||
log[0][3],
|
||||
log[0][4],
|
||||
log[0][5] || GameCommon.SCORE_MODE_FINAL
|
||||
)
|
||||
notify(
|
||||
[Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log],
|
||||
[socket]
|
||||
)
|
||||
} break
|
||||
|
||||
case Protocol.EV_CLIENT_INIT: {
|
||||
if (!Game.exists(gameId)) {
|
||||
throw `[game ${gameId} does not exist... ]`
|
||||
}
|
||||
const ts = Time.timestamp()
|
||||
Game.addPlayer(gameId, clientId, ts)
|
||||
GameSockets.addSocket(gameId, socket)
|
||||
const game = Game.get(gameId)
|
||||
notify(
|
||||
[Protocol.EV_SERVER_INIT, Util.encodeGame(game)],
|
||||
[socket]
|
||||
)
|
||||
} break
|
||||
|
||||
case Protocol.EV_CLIENT_EVENT: {
|
||||
if (!Game.exists(gameId)) {
|
||||
throw `[game ${gameId} does not exist... ]`
|
||||
}
|
||||
const clientSeq = msg[1]
|
||||
const clientEvtData = msg[2]
|
||||
const ts = Time.timestamp()
|
||||
|
||||
let sendGame = false
|
||||
if (!Game.playerExists(gameId, clientId)) {
|
||||
Game.addPlayer(gameId, clientId, ts)
|
||||
sendGame = true
|
||||
}
|
||||
if (!GameSockets.socketExists(gameId, socket)) {
|
||||
GameSockets.addSocket(gameId, socket)
|
||||
sendGame = true
|
||||
}
|
||||
if (sendGame) {
|
||||
const game = Game.get(gameId)
|
||||
notify(
|
||||
[Protocol.EV_SERVER_INIT, Util.encodeGame(game)],
|
||||
[socket]
|
||||
)
|
||||
}
|
||||
|
||||
const changes = Game.handleInput(gameId, clientId, clientEvtData, ts)
|
||||
notify(
|
||||
[Protocol.EV_SERVER_EVENT, clientId, clientSeq, changes],
|
||||
GameSockets.getSockets(gameId)
|
||||
)
|
||||
} break
|
||||
}
|
||||
} catch (e) {
|
||||
log.error(e)
|
||||
}
|
||||
})
|
||||
|
||||
GameStorage.loadGames()
|
||||
const server = app.listen(
|
||||
port,
|
||||
hostname,
|
||||
() => log.log(`server running on http://${hostname}:${port}`)
|
||||
)
|
||||
wss.listen()
|
||||
|
||||
|
||||
const memoryUsageHuman = () => {
|
||||
const totalHeapSize = v8.getHeapStatistics().total_available_size
|
||||
let totalHeapSizeInGB = (totalHeapSize / 1024 / 1024 / 1024).toFixed(2)
|
||||
|
||||
log.log(`Total heap size (bytes) ${totalHeapSize}, (GB ~${totalHeapSizeInGB})`)
|
||||
const used = process.memoryUsage().heapUsed / 1024 / 1024
|
||||
log.log(`Mem: ${Math.round(used * 100) / 100}M`)
|
||||
}
|
||||
|
||||
memoryUsageHuman()
|
||||
|
||||
// persist games in fixed interval
|
||||
const persistInterval = setInterval(() => {
|
||||
log.log('Persisting games...')
|
||||
GameStorage.persistGames()
|
||||
|
||||
memoryUsageHuman()
|
||||
}, config.persistence.interval)
|
||||
|
||||
const gracefulShutdown = (signal) => {
|
||||
log.log(`${signal} received...`)
|
||||
|
||||
log.log('clearing persist interval...')
|
||||
clearInterval(persistInterval)
|
||||
|
||||
log.log('persisting games...')
|
||||
GameStorage.persistGames()
|
||||
|
||||
log.log('shutting down webserver...')
|
||||
server.close()
|
||||
|
||||
log.log('shutting down websocketserver...')
|
||||
wss.close()
|
||||
|
||||
log.log('shutting down...')
|
||||
process.exit()
|
||||
}
|
||||
|
||||
// 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