diff rlgwebd.js @ 47:27b7f0c8b9f0

RLG-Web: make login sessions time out. After enough inactivity, log the user out automatically.
author John "Elwin" Edwards <elwin@sdf.org>
date Sat, 09 Jun 2012 21:20:14 -0700
parents c4efc7522e7b
children 423ef87ddc9b
line wrap: on
line diff
--- a/rlgwebd.js	Sat Jun 09 17:00:25 2012 -0700
+++ b/rlgwebd.js	Sat Jun 09 21:20:14 2012 -0700
@@ -59,7 +59,7 @@
  * been authenticated.
  */
 /* TODO take a callback, or emit success/err events. */
-function TermSession(game, user, dims) {
+function TermSession(game, user, dims, lkey) {
   /* First make sure starting the game will work. */
   if (game in games) {
     this.game = games[game];
@@ -69,6 +69,7 @@
     return null;
   }
   this.player = String(user);
+  this.key = lkey;
   /* This order seems to best avoid race conditions... */
   this.alive = false;
   this.sessid = randkey(2);
@@ -361,6 +362,14 @@
     fs.fstat(session.record.fd, function (err, stats) {
       if (!err && now - stats.mtime > playtimeout) {
         tslog("Reaping %s", session.sessid);
+        /* Dissociate it with its login name. */
+        var sn = logins[session.key].sessions.indexOf(session.sessid);
+        if (sn >= 0) {
+          logins[session.key].sessions.splice(sn, 1);
+          if (now - logins[session.key].ts > playtimeout)
+            logins[session.key].ts = new Date(now - playtimeout);
+        }
+        /* Shut it down. */
         session.close();
       }
     });
@@ -368,6 +377,35 @@
   for (var sessid in sessions) {
     reapcheck(sessions[sessid]);
   }
+  /* HELPME this is about as clever as I can code, so I can't tell whether
+   * there are any bugs. */
+  for (var lkey in logins) {
+    if (logins[lkey].sessions.length == 0) {
+      /* A login with no current games can be killed for inactivity. */
+      if (now - logins[lkey].ts > playtimeout * 4) {
+        tslog("Login for %s (key %s) timed out", logins[lkey].name, lkey);
+        delete logins[lkey];
+      }
+    }
+    else {
+      /* Check for games that have terminated normally, and update
+       * the timestamp. */
+      var expired = [];
+      var targarray = logins[lkey].sessions;
+      /* Let's not find out what happens if you modify an array
+       * you're iterating through. */
+      for (var i = 0; i < targarray.length; i++) {
+        if (!(targarray[i] in sessions))
+          expired.push(targarray[i]);
+      }
+      if (expired.length > 0) {
+        logins[lkey].ts = new Date(now);
+        for (var j = 0; j < expired.length; j++) {
+          targarray.splice(targarray.indexOf(expired[j], 1));
+        }
+      }
+    }
+  }
 }
 
 function login(req, res, formdata) {
@@ -400,7 +438,7 @@
     var lkey = randkey(2);
     while (lkey in logins)
       lkey = randkey(2);
-    logins[lkey] = {"name": username, "ts": new Date()};
+    logins[lkey] = {"name": username, "ts": new Date(), "sessions": []};
     res.writeHead(200, {'Content-Type': 'application/json'});
     var reply = {"t": "l", "k": lkey, "u": username};
     res.write(JSON.stringify(reply));
@@ -452,7 +490,7 @@
       return;
     }
     // Game starting has been approved.
-    var nsession = new TermSession(gname, username, dims);
+    var nsession = new TermSession(gname, username, dims, lkey);
     if (nsession) {
       res.writeHead(200, {'Content-Type': 'application/json'});
       var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": 
@@ -461,6 +499,7 @@
       res.end();
       tslog("%s playing %s (key %s, pid %d)", username, gname, 
                   nsession.sessid, nsession.child.pid);
+      logins[lkey].sessions.push(nsession.sessid);
     }
     else {
       sendError(res, 5, "Failed to open TTY");
@@ -506,7 +545,7 @@
       var lkey = randkey(2);
       while (lkey in logins)
         lkey = randkey(2);
-      logins[lkey] = {"name": uname, "ts": new Date()};
+      logins[lkey] = {"name": uname, "ts": new Date(), "sessions": []};
       var reply = {"t": "r", "k": lkey, "u": uname};
       res.writeHead(200, {'Content-Type': 'application/json'});
       res.write(JSON.stringify(reply));