merge the /game/ and /meta/ GET handlers

This commit is contained in:
Jesse D. McDonald 2020-04-27 20:21:18 -05:00
parent 012bc7ea09
commit 674b460cbe
1 changed files with 14 additions and 104 deletions

118
index.js
View File

@ -40,28 +40,6 @@ var appendJournal = (function() {
};
})();
function logIn(msg){
console.log(`in msg:${JSON.stringify(msg)}.........`);
}
function logOut(msg){
console.log(`out msg:${JSON.stringify(msg)}.........`);
}
function logPeers() {
console.log(`Peers: ${Object.keys(gun._.opt.peers).join(', ')}`);
}
function logData() {
console.log(`In Memory: ${JSON.stringify(gun._.graph)}`);
}
//gun._.on('in', logIn);
//gun._.on('out', logOut);
//setInterval(logPeers, 5000); //Log peer list every 5 secs
//setInterval(logData, 20000); //Log gun graph every 20 secs
function logDbError(label) {
return function(err) {
console.error(label + ':', ((err && err.message) || err));
@ -115,20 +93,6 @@ function pruneEmpty(obj) {
return copy;
}
async function logAllMeta() {
const db = await dbInit;
try {
const querySql = `
SELECT gameId, lightName, darkName, moves, status, timestamp FROM games ORDER BY timestamp DESC
`;
for await (const row of db.eachAsync(querySql)) {
console.log(JSON.stringify(pruneEmpty(row)));
}
} catch(err) {
logDbError('logAllMeta')(err);
}
}
let waitingAnyGame = null;
const waitingGames = {};
@ -168,8 +132,6 @@ function waitFor(duration) {
return new Promise((resolve, reject) => setTimeout(() => { resolve(); }, duration));
}
//logAllMeta();
function checkString(value, label, dflt) {
try {
if (arguments.length >= 3 && (value === undefined || value === null)) {
@ -388,18 +350,23 @@ async function getGameHandler(req, res, next) {
const gameUpdate = waitForGameUpdate(gameId).then(() => 'update');
const querySql = `
SELECT board, modified FROM games WHERE gameId = $gameId
SELECT lightName, darkName, moves, status, timestamp, board, modified FROM games
WHERE gameId = $gameId
`;
const result = await (await dbInit).getAsync(querySql, { $gameId: gameId });
if (!result) {
res.status(404).json({ message: 'unknown game ID' });
if (result && (afterTime === undefined || result.modified > afterTime)) {
if (req.params.type === 'meta') {
delete result.board;
} else {
result.board = (result.board === '') ? null : JSON.parse(result.board);
}
res.json(pruneEmpty(result));
return;
}
if (afterTime === undefined || result.modified > afterTime) {
const parsed = (result.board === '') ? null : JSON.parse(result.board);
res.json({ board: parsed, modified: result.modified });
if (afterTime === undefined) {
res.status(404).json({ message: 'unknown game ID' });
return;
}
@ -413,54 +380,6 @@ async function getGameHandler(req, res, next) {
}
}
async function getMetaHandler(req, res, next) {
res.set('Cache-Control', 'no-store');
try {
const gameId = req.params.gameId;
const afterTime = req.params.afterTime;
if (!gameId.match(/^[0-9a-f]{16}$/)) {
res.status(400).json({ message: 'malformed game ID' });
return;
}
if (afterTime !== undefined && !afterTime.match(/^\d+$/)) {
res.status(400).json({ message: 'malformed time' });
return;
}
const pollTimeout = waitFor(POLLING_TIMEOUT).then(() => 'timeout').catch(()=>{});
while (true) {
/* Save the async promise _before_ the query so we don't miss any updates while suspended. */
const metaUpdate = waitForGameUpdate(gameId).then(() => 'update');
const querySql = `
SELECT lightName, darkName, moves, status, timestamp, modified FROM games
WHERE gameId = $gameId
`;
const result = await (await dbInit).getAsync(querySql, { $gameId: gameId });
if (!result) {
res.status(404).json({ message: 'unknown game ID' });
return;
}
if (afterTime === undefined || result.modified > afterTime) {
res.json(pruneEmpty(result));
return;
}
if (await Promise.race([metaUpdate, pollTimeout]) === 'timeout') {
res.status(204).json({ retry: true });
return;
}
}
} catch (err) {
internalErrorJson(err, res);
}
}
const updateTemplate = {
lightName(x) { return typeof x === 'string'; },
darkName(x) { return typeof x === 'string'; },
@ -474,22 +393,18 @@ const updateTemplate = {
function validateUpdate(body) {
try {
if (typeof body !== 'object' || 'modified' in body === false) {
console.log('invalid type or missing modified property');
return null;
}
for (const key in body) {
if (key in updateTemplate === false) {
console.log('extra key', key);
return null;
}
if (updateTemplate[key](body[key]) === false) {
console.log('invalid value', body[key], 'for key', key);
return null;
}
}
} catch(err) {
console.log('exception', err);
return null;
}
@ -503,8 +418,6 @@ async function postGameHandler(req, res, next) {
const gameId = req.params.gameId;
const body = validateUpdate(req.body);
console.log('update for', gameId, 'at time', time, req.body, !body);
if (!gameId.match(/^[0-9a-f]{16}$/)) {
res.status(400).json({ message: 'malformed game ID' });
return;
@ -625,12 +538,9 @@ async function postGameHandler(req, res, next) {
app.get('/pacosako/api/games/poll/:afterTime', getGameListHandler);
app.get('/pacosako/api/games', getGameListHandler);
app.get('/pacosako/api/game/:gameId/poll/:afterTime', getGameHandler);
app.get('/pacosako/api/game/:gameId', getGameHandler);
app.post('/pacosako/api/game/:gameId', express.json(), postGameHandler);
app.get('/pacosako/api/meta/:gameId/poll/:afterTime', getMetaHandler);
app.get('/pacosako/api/meta/:gameId', getMetaHandler);
app.get('/pacosako/api/:type(game|meta)/:gameId/poll/:afterTime', getGameHandler);
app.get('/pacosako/api/:type(game|meta)/:gameId', getGameHandler);
app.post('/pacosako/api/:type(game|meta)/:gameId', express.json(), postGameHandler);
app.use('/pacosako/api', express.static('public'));