changeset 40:f7116eb3f791

rlgwebd.js: refactor some game-starting code. Separate things like checking for games in progress, starting a new game, and figuring out where the lockfile and ttyrec should go. This allows e.g. the games-in-progress check to be used to create status messages. It also keeps the argument list for the TermSession constructor to a sensible size.
author John "Elwin" Edwards <elwin@sdf.org>
date Fri, 08 Jun 2012 18:11:47 -0700
parents e8ac0e3d2614
children ea3b7775009d
files rlgwebd.js
diffstat 1 files changed, 42 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/rlgwebd.js	Thu Jun 07 15:43:06 2012 -0700
+++ b/rlgwebd.js	Fri Jun 08 18:11:47 2012 -0700
@@ -54,7 +54,8 @@
  * adds itself to the sessions dict. It currently assumes the user has
  * been authenticated.
  */
-function TermSession(game, user, files, dims) {
+/* TODO take a callback, or emit success/err events. */
+function TermSession(game, user, dims) {
   /* First make sure starting the game will work. */
   if (game in games) {
     this.game = games[game];
@@ -63,7 +64,7 @@
     // TODO: throw an exception instead
     return null;
   }
-  this.player = user;
+  this.player = String(user);
   /* This order seems to best avoid race conditions... */
   this.alive = false;
   this.sessid = randkey(2);
@@ -97,10 +98,15 @@
   var ss = this;
   this.alive = true;
   this.data = [];
-  this.lock = files[0];
-  fs.writeFile(this.lock, this.child.pid.toString() + '\n' + this.w + '\n' +
-               this.h + '\n', "utf8"); 
-  this.record = fs.createWriteStream(files[1], { mode: 0664 });
+  /* Set up the lockfile and ttyrec */
+  var ts = timestamp();
+  var progressdir = "/dgldir/inprogress-" + this.game.uname;
+  this.lock = path.join(progressdir, this.player + ":node:" + ts + ".ttyrec");
+  var lmsg = this.child.pid.toString() + '\n' + this.w + '\n' + this.h + '\n'; 
+  fs.writeFile(this.lock, lmsg, "utf8"); 
+  var ttyrec = path.join("/dgldir/ttyrec", this.player, this.game.uname, 
+               ts + ".ttyrec");
+  this.record = fs.createWriteStream(ttyrec, { mode: 0664 });
   /* END setup */
   function ttyrec_chunk(buf) {
     var ts = new Date();
@@ -219,6 +225,27 @@
   };
 }
 
+function checkprogress(user, game, callback, args) {
+  var progressdir = "/dgldir/inprogress-" + game.uname;
+  fs.readdir(progressdir, function(err, files) {
+    if (err) {
+      args.unshift(err, null);
+      callback.apply(null, args);
+      return;
+    }
+    var fre = RegExp("^" + user + ":");
+    for (var i = 0; i < files.length; i++) {
+      if (files[i].match(fre)) {
+        args.shift(null, files[i]);
+        callback.apply(null, args);
+        return;
+      }
+    }
+    args.shift(null, false);
+    callback.apply(null, args);
+  });
+}
+
 /* A few utility functions */
 function timestamp() {
   dd = new Date();
@@ -374,28 +401,16 @@
     tslog("Request for nonexistant game \"%s\"", gname);
     return;
   }
-  // check for an existing game
-  var progressdir = "/dgldir/inprogress-" + games[gname].uname;
-  fs.readdir(progressdir, function(err, files) {
-    if (!err) {
-      var fre = RegExp("^" + username + ":");
-      for (var i = 0; i < files.length; i++) {
-        if (files[i].match(fre)) {
-          sendError(res, 4, null);
-          tslog("%s is already playing %s", username, gname);
-          return;
-        }
-      }
+  // A callback to pass to the game-in-progress checker.
+  var launch = function(err, fname) {
+    if (fname) {
+      sendError(res, 4, null);
+      tslog("%s is already playing %s", username, gname);
+      return;
     }
     // Game starting has been approved.
-    var ts = timestamp();
-    var lockfile = path.join(progressdir, username + ":node:" + ts + ".ttyrec");
-    var ttyrec = path.join("/dgldir/ttyrec", username, gname, ts + ".ttyrec");
-    var nsession = new TermSession(gname, username, [lockfile, ttyrec], dims);
+    var nsession = new TermSession(gname, username, dims);
     if (nsession) {
-      /* Technically there's a race condition for the "lock"file, but since 
-       * it requires the user deliberately starting two games at similar times, 
-       * it's not too serious. We can't get O_EXCL in Node anyway. */
       res.writeHead(200, {'Content-Type': 'application/json'});
       var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": 
                    nsession.h};
@@ -408,7 +423,8 @@
       sendError(res, 5, "Failed to open TTY");
       tslog("Unable to allocate TTY for %s", gname);
     }
-  });
+  }
+  checkprogress(username, games[gname], launch, []);
 }
 
 /* Sets things up for a new user, like dgamelaunch's commands[register] */