Implement cleaning methods (CRON tasks)
[vchess.git] / server / models / Game.js
index f99dbde..77bbd27 100644 (file)
@@ -8,20 +8,19 @@ var db = require("../utils/database");
  *   fen: varchar (current position)
  *   timeControl: string
  *   score: varchar (result)
+ *   created: datetime
  *
  * Structure table Players:
  *   gid: ref game id
  *   uid: ref user id
  *   color: character
- *   rtime: real (remaining time)
  *
  * Structure table Moves:
  *   gid: ref game id
- *   move: varchar (description)
+ *   squares: varchar (description)
  *   message: text
  *   played: datetime
  *   idx: integer
- *   color: character
  */
 
 const GameModel =
@@ -30,17 +29,17 @@ const GameModel =
        {
                db.serialize(function() {
                        let query =
-                               "INSERT INTO Games (vid, fenStart, score, timeControl) " +
-                               "VALUES (" + vid + ",'" + fen + "','*','" + timeControl + "')";
+                               "INSERT INTO Games (vid, fenStart, fen, score, timeControl, created)"
+        + " VALUES (" + vid + ",'" + fen + "','" + fen + "','*','"
+        + timeControl + "'," + Date.now() + ")";
       db.run(query, function(err) {
-                               if (!!err)
-                                       return cb(err);
+        if (!!err)
+          return cb(err);
         players.forEach((p,idx) => {
           const color = (idx==0 ? "w" : "b");
           query =
             "INSERT INTO Players VALUES " +
-            // Remaining time = -1 means "unstarted"
-            "(" + this.lastID + "," + p.id + ",'" + color + "', -1)";
+            "(" + this.lastID + "," + p.id + ",'" + color + "')";
           db.run(query);
         });
         cb(null, {gid: this.lastID});
@@ -52,22 +51,28 @@ const GameModel =
        getOne: function(id, cb)
        {
                db.serialize(function() {
+      // TODO: optimize queries?
                        let query =
-                               "SELECT * " +
-                               "FROM Games " +
-                               "WHERE id = " + id;
+                               "SELECT g.id, g.vid, g.fen, g.fenStart, g.timeControl, g.score, " +
+          "v.name AS vname " +
+                               "FROM Games g " +
+        "JOIN Variants v " +
+        "  ON g.vid = v.id " +
+                               "WHERE g.id = " + id;
                        db.get(query, (err,gameInfo) => {
                                if (!!err)
                                        return cb(err);
                                query =
-                                       "SELECT uid, color, rtime " +
-                                       "FROM Players " +
-                                       "WHERE gid = " + id;
+                                       "SELECT p.uid, p.color, u.name " +
+                                       "FROM Players p " +
+          "JOIN Users u " +
+          "  ON p.uid = u.id " +
+                                       "WHERE p.gid = " + id;
                                db.all(query, (err2,players) => {
                                        if (!!err2)
                                                return cb(err2);
                                        query =
-                                               "SELECT move, message, played, idx, color " +
+                                               "SELECT squares, message, played, idx " +
                                                "FROM Moves " +
                                                "WHERE gid = " + id;
                                        db.all(query, (err3,moves) => {
@@ -95,23 +100,65 @@ const GameModel =
                                "SELECT gid " +
                                "FROM Players " +
                                "WHERE uid " + (excluded ? "<>" : "=") + " " + uid;
-                       db.run(query, (err,gameIds) => {
+                       db.all(query, (err,gameIds) => {
                                if (!!err)
                                        return cb(err);
         gameIds = gameIds || []; //might be empty
                                let gameArray = [];
-                               gameIds.forEach(gidRow => {
-                                       GameModel.getOne(gidRow["gid"], (err2,game) => {
+                               for (let i=0; i<gameIds.length; i++)
+                               {
+                                       GameModel.getOne(gameIds[i]["gid"], (err2,game) => {
                                                if (!!err2)
                                                        return cb(err2);
                                                gameArray.push(game);
+                                               // Call callback function only when gameArray is complete:
+                                               if (i == gameIds.length - 1)
+                                                       return cb(null, gameArray);
                                        });
-                               });
-                               return cb(null, gameArray);
+                               }
                        });
                });
        },
 
+  getPlayers: function(id, cb)
+  {
+    db.serialize(function() {
+      const query =
+        "SELECT id " +
+        "FROM Players " +
+        "WHERE gid = " + id;
+      db.all(query, (err,players) => {
+        return cb(err, players);
+      });
+    });
+  },
+
+  // obj can have fields move, fen and/or score
+  update: function(id, obj)
+  {
+               db.parallelize(function() {
+      let query =
+        "UPDATE Games " +
+        "SET ";
+      if (!!obj.fen)
+        query += "fen = '" + obj.fen + "',";
+      if (!!obj.score)
+        query += "score = '" + obj.score + "',";
+      query = query.slice(0,-1); //remove last comma
+      query += " WHERE id = " + id;
+      db.run(query);
+      if (!!obj.move)
+      {
+        const m = obj.move;
+        query =
+          "INSERT INTO Moves (gid, squares, message, played, idx) VALUES " +
+          "(" + id + ",'" + JSON.stringify(m.squares) + "','" + m.message +
+            "'," + m.played + "," + m.idx + ")";
+        db.run(query);
+      }
+    });
+  },
+
        remove: function(id)
        {
                db.parallelize(function() {
@@ -129,6 +176,36 @@ const GameModel =
                        db.run(query);
                });
        },
+
+  cleanGamesDb: function()
+  {
+    const tsNow = Date.now();
+    // 86400000 = 24 hours in milliseconds
+    const day = 86400000;
+    db.serialize(function() {
+      let query =
+        "SELECT id,score " +
+        "FROM Games ";
+      db.all(query, (err,games) => {
+        games.forEach(g => {
+          query =
+            "SELECT 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)
+            {
+              GameModel.remove(g.id);
+            }
+          });
+        });
+      });
+    });
+  },
 }
 
 module.exports = GameModel;