merge the /game/ and /meta/ GET handlers
This commit is contained in:
parent
012bc7ea09
commit
674b460cbe
120
index.js
120
index.js
|
|
@ -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) {
|
function logDbError(label) {
|
||||||
return function(err) {
|
return function(err) {
|
||||||
console.error(label + ':', ((err && err.message) || err));
|
console.error(label + ':', ((err && err.message) || err));
|
||||||
|
|
@ -115,20 +93,6 @@ function pruneEmpty(obj) {
|
||||||
return copy;
|
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;
|
let waitingAnyGame = null;
|
||||||
const waitingGames = {};
|
const waitingGames = {};
|
||||||
|
|
||||||
|
|
@ -168,8 +132,6 @@ function waitFor(duration) {
|
||||||
return new Promise((resolve, reject) => setTimeout(() => { resolve(); }, duration));
|
return new Promise((resolve, reject) => setTimeout(() => { resolve(); }, duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
//logAllMeta();
|
|
||||||
|
|
||||||
function checkString(value, label, dflt) {
|
function checkString(value, label, dflt) {
|
||||||
try {
|
try {
|
||||||
if (arguments.length >= 3 && (value === undefined || value === null)) {
|
if (arguments.length >= 3 && (value === undefined || value === null)) {
|
||||||
|
|
@ -388,70 +350,27 @@ async function getGameHandler(req, res, next) {
|
||||||
const gameUpdate = waitForGameUpdate(gameId).then(() => 'update');
|
const gameUpdate = waitForGameUpdate(gameId).then(() => 'update');
|
||||||
|
|
||||||
const querySql = `
|
const querySql = `
|
||||||
SELECT board, modified FROM games WHERE gameId = $gameId
|
SELECT lightName, darkName, moves, status, timestamp, board, modified FROM games
|
||||||
`;
|
|
||||||
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) {
|
|
||||||
const parsed = (result.board === '') ? null : JSON.parse(result.board);
|
|
||||||
res.json({ board: parsed, modified: result.modified });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await Promise.race([gameUpdate, pollTimeout]) === 'timeout') {
|
|
||||||
res.status(204).json({ retry: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(err) {
|
|
||||||
internalErrorJson(err, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
WHERE gameId = $gameId
|
||||||
`;
|
`;
|
||||||
const result = await (await dbInit).getAsync(querySql, { $gameId: gameId });
|
const result = await (await dbInit).getAsync(querySql, { $gameId: gameId });
|
||||||
|
|
||||||
if (!result) {
|
if (result && (afterTime === undefined || result.modified > afterTime)) {
|
||||||
res.status(404).json({ message: 'unknown game ID' });
|
if (req.params.type === 'meta') {
|
||||||
return;
|
delete result.board;
|
||||||
|
} else {
|
||||||
|
result.board = (result.board === '') ? null : JSON.parse(result.board);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (afterTime === undefined || result.modified > afterTime) {
|
|
||||||
res.json(pruneEmpty(result));
|
res.json(pruneEmpty(result));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await Promise.race([metaUpdate, pollTimeout]) === 'timeout') {
|
if (afterTime === undefined) {
|
||||||
|
res.status(404).json({ message: 'unknown game ID' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await Promise.race([gameUpdate, pollTimeout]) === 'timeout') {
|
||||||
res.status(204).json({ retry: true });
|
res.status(204).json({ retry: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -474,22 +393,18 @@ const updateTemplate = {
|
||||||
function validateUpdate(body) {
|
function validateUpdate(body) {
|
||||||
try {
|
try {
|
||||||
if (typeof body !== 'object' || 'modified' in body === false) {
|
if (typeof body !== 'object' || 'modified' in body === false) {
|
||||||
console.log('invalid type or missing modified property');
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key in body) {
|
for (const key in body) {
|
||||||
if (key in updateTemplate === false) {
|
if (key in updateTemplate === false) {
|
||||||
console.log('extra key', key);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (updateTemplate[key](body[key]) === false) {
|
if (updateTemplate[key](body[key]) === false) {
|
||||||
console.log('invalid value', body[key], 'for key', key);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.log('exception', err);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,8 +418,6 @@ async function postGameHandler(req, res, next) {
|
||||||
const gameId = req.params.gameId;
|
const gameId = req.params.gameId;
|
||||||
const body = validateUpdate(req.body);
|
const body = validateUpdate(req.body);
|
||||||
|
|
||||||
console.log('update for', gameId, 'at time', time, req.body, !body);
|
|
||||||
|
|
||||||
if (!gameId.match(/^[0-9a-f]{16}$/)) {
|
if (!gameId.match(/^[0-9a-f]{16}$/)) {
|
||||||
res.status(400).json({ message: 'malformed game ID' });
|
res.status(400).json({ message: 'malformed game ID' });
|
||||||
return;
|
return;
|
||||||
|
|
@ -625,12 +538,9 @@ async function postGameHandler(req, res, next) {
|
||||||
app.get('/pacosako/api/games/poll/:afterTime', getGameListHandler);
|
app.get('/pacosako/api/games/poll/:afterTime', getGameListHandler);
|
||||||
app.get('/pacosako/api/games', getGameListHandler);
|
app.get('/pacosako/api/games', getGameListHandler);
|
||||||
|
|
||||||
app.get('/pacosako/api/game/:gameId/poll/:afterTime', getGameHandler);
|
app.get('/pacosako/api/:type(game|meta)/:gameId/poll/:afterTime', getGameHandler);
|
||||||
app.get('/pacosako/api/game/:gameId', getGameHandler);
|
app.get('/pacosako/api/:type(game|meta)/:gameId', getGameHandler);
|
||||||
app.post('/pacosako/api/game/:gameId', express.json(), postGameHandler);
|
app.post('/pacosako/api/:type(game|meta)/:gameId', express.json(), postGameHandler);
|
||||||
|
|
||||||
app.get('/pacosako/api/meta/:gameId/poll/:afterTime', getMetaHandler);
|
|
||||||
app.get('/pacosako/api/meta/:gameId', getMetaHandler);
|
|
||||||
|
|
||||||
app.use('/pacosako/api', express.static('public'));
|
app.use('/pacosako/api', express.static('public'));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue