X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=server%2Fmodels%2FGame.js;h=fb249a7c8d6a085e5e133ef2b915e06d5c8b02e3;hb=c5c47010b5b50edbdd6bfc40a61ce716c6114e5a;hp=da59b4a6dbe6433e84beeceaa501b13fc12f0f0d;hpb=dac395887d96e2d642b209c6db6aaacc3ffacb34;p=vchess.git diff --git a/server/models/Game.js b/server/models/Game.js index da59b4a6..fb249a7c 100644 --- a/server/models/Game.js +++ b/server/models/Game.js @@ -1,4 +1,4 @@ -var db = require("../utils/database"); +const db = require("../utils/database"); const UserModel = require("./User"); /* @@ -7,11 +7,11 @@ const UserModel = require("./User"); * vid: integer (variant id) * fenStart: varchar (initial position) * fen: varchar (current position) - * timeControl: string + * cadence: string * score: varchar (result) * scoreMsg: varchar ("Time", "Mutual agreement"...) * created: datetime - * drawOffer: boolean + * drawOffer: char ('w','b' or '' for none) * * Structure table Players: * gid: ref game id @@ -36,9 +36,7 @@ const GameModel = checkGameInfo: function(g) { if (!g.vid.toString().match(/^[0-9]+$/)) return "Wrong variant ID"; - if (!g.vname.match(/^[a-zA-Z0-9]+$/)) - return "Wrong variant name"; - if (!g.timeControl.match(/^[0-9dhms +]+$/)) + if (!g.cadence.match(/^[0-9dhms +]+$/)) return "Wrong characters in time control"; if (!g.fen.match(/^[a-zA-Z0-9, /-]*$/)) return "Bad FEN string"; @@ -49,14 +47,14 @@ const GameModel = return ""; }, - create: function(vid, fen, timeControl, players, cb) + create: function(vid, fen, cadence, players, cb) { db.serialize(function() { let query = - "INSERT INTO Games" - + " (vid, fenStart, fen, score, timeControl, created, drawOffer)" - + " VALUES (" + vid + ",'" + fen + "','" + fen + "','*','" - + timeControl + "'," + Date.now() + "," + false + ")"; + "INSERT INTO Games " + + "(vid, fenStart, fen, score, cadence, created, drawOffer) " + + "VALUES " + + "(" + vid + ",'" + fen + "','" + fen + "','*','" + cadence + "'," + Date.now() + ",'')"; db.run(query, function(err) { if (!!err) return cb(err); @@ -72,16 +70,15 @@ const GameModel = }); }, - // TODO: queries here could be async, and wait for all to complete - getOne: function(id, cb) + // TODO: some queries here could be async + getOne: function(id, light, cb) { db.serialize(function() { - // TODO: optimize queries? let query = // NOTE: g.scoreMsg can be NULL // (in this case score = "*" and no reason to look at it) - "SELECT g.id, g.vid, g.fen, g.fenStart, g.timeControl, g.score, " + - "g.scoreMsg, v.name AS vname " + + "SELECT g.id, g.vid, g.fen, g.fenStart, g.cadence, g.created, g.score, " + + "g.scoreMsg, g.drawOffer, v.name AS vname " + "FROM Games g " + "JOIN Variants v " + " ON g.vid = v.id " + @@ -98,6 +95,14 @@ const GameModel = db.all(query, (err2,players) => { if (!!err2) return cb(err2); + if (light) + { + const game = Object.assign({}, + gameInfo, + {players: players} + ); + return cb(null, game); + } query = "SELECT squares, played, idx " + "FROM Moves " + @@ -128,27 +133,42 @@ const GameModel = }); }, + // For display on MyGames or Hall: no need for moves or chats getByUser: function(uid, excluded, cb) { db.serialize(function() { - // Next query is fine because a player appear at most once in a game - const query = - "SELECT gid " + - "FROM Players " + - "WHERE uid " + (excluded ? "<>" : "=") + " " + uid; + let query = ""; + if (uid == 0) + { + // Special case anonymous user: show all games + query = + "SELECT id AS gid " + + "FROM Games"; + } + else + { + // Registered user: + query = + "SELECT gid " + + "FROM Players " + + "GROUP BY gid " + + "HAVING COUNT(uid = " + uid + " OR NULL) " + + (excluded ? " = 0" : " > 0"); + } db.all(query, (err,gameIds) => { - if (!!err) - return cb(err); - gameIds = gameIds || []; //might be empty + if (!!err || gameIds.length == 0) + return cb(err, []); let gameArray = []; + let kounter = 0; for (let i=0; i { + GameModel.getOne(gameIds[i]["gid"], true, (err2,game) => { if (!!err2) return cb(err2); gameArray.push(game); + kounter++; //TODO: let's hope this is atomic?! // Call callback function only when gameArray is complete: - if (i == gameIds.length - 1) + if (kounter == gameIds.length) return cb(null, gameArray); }); } @@ -160,7 +180,7 @@ const GameModel = { db.serialize(function() { const query = - "SELECT id " + + "SELECT uid " + "FROM Players " + "WHERE gid = " + id; db.all(query, (err,players) => { @@ -179,6 +199,8 @@ const GameModel = if (!obj.move.idx.toString().match(/^[0-9]+$/)) return "Wrong move index"; } + if (!!obj.drawOffer && !obj.drawOffer.match(/^[wbtn]$/)) + return "Wrong draw offer format"; if (!!obj.fen && !obj.fen.match(/^[a-zA-Z0-9, /-]*$/)) return "Wrong FEN string"; if (!!obj.score && !obj.score.match(/^[012?*\/-]+$/)) @@ -200,8 +222,14 @@ const GameModel = let modifs = ""; if (!!obj.message) modifs += "message = message || ' ' || '" + obj.message + "',"; - if ([true,false].includes(obj.drawOffer)) - modifs += "drawOffer = " + obj.drawOffer + ","; + // NOTE: if drawOffer is set, we should check that it's player's turn + // A bit overcomplicated. Let's trust the client on that for now... + if (!!obj.drawOffer) + { + if (obj.drawOffer == "n") //Special "None" update + obj.drawOffer = ""; + modifs += "drawOffer = '" + obj.drawOffer + "',"; + } if (!!obj.fen) modifs += "fen = '" + obj.fen + "',"; if (!!obj.score) @@ -261,20 +289,19 @@ const GameModel = const day = 86400000; db.serialize(function() { let query = - "SELECT id,score " + + "SELECT id, created " + "FROM Games "; db.all(query, (err,games) => { games.forEach(g => { query = - "SELECT max(played) AS lastMaj " + + "SELECT count(*) as nbMoves, max(played) AS lastMaj " + "FROM Moves " + "WHERE gid = " + g.id; - db.get(query, (err2,updated) => { - if (!updated && tsNow - g.created > 7*day) - return GameModel.remove(g.id); - const lastMaj = updated.lastMaj; - if (g.score != "*" && tsNow - lastMaj > 7*day || - g.score == "*" && tsNow - lastMaj > 91*day) + db.get(query, (err2,mstats) => { + // Remove games still not really started, + // with no action in the last 3 months: + if ((mstats.nbMoves == 0 && tsNow - g.created > 91*day) || + (mstats.nbMoves == 1 && tsNow - mstats.lastMaj > 91*day)) { GameModel.remove(g.id); }