changeset 111:f56fdfeed01a

Replace taking over games with forced saves. Instead of reusing the id, just SIGHUP the game process. This works whether it is using polling, WebSockets, or dgamelaunch.
author John "Elwin" Edwards <elwin@sdf.org>
date Sun, 15 Jul 2012 22:33:44 -0700
parents 18a81cc0084b
children 4f2b89e6fde2
files rlgterm.js rlgwebd.js
diffstat 2 files changed, 84 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/rlgterm.js	Sun Jul 15 21:03:36 2012 -0700
+++ b/rlgterm.js	Sun Jul 15 22:33:44 2012 -0700
@@ -622,18 +622,20 @@
         acttext = "Resume your game";
       else if (reply.stat[gname] == "0")
         acttext = "Start a game";
-      else if (reply.stat[gname] == "p")
-        acttext = "Reconnect";
-      else if (reply.stat[gname] == "d")
-        acttext = "Game in progress (dgl)";
+      else if (reply.stat[gname] == "p" || reply.stat[gname] == "d")
+        acttext = "Force save";
       else
         continue;
       var button = document.createElement("span");
       button.appendChild(document.createTextNode(acttext));
-      if ("s0p".indexOf(reply.stat[gname]) >= 0) {
+      if ("s0".indexOf(reply.stat[gname]) >= 0) {
         button.onclick = makeStarter(gname);
         button.className = "ibutton";
       }
+      else {
+        button.onclick = makeStopper(gname);
+        button.className = "ibutton";
+      }
       var actdiv = document.createElement("div");
       actdiv.appendChild(button);
       var gamediv = document.createElement("div");
@@ -719,6 +721,44 @@
   return;
 }
 
+function makeStopper(gname) {
+  if (!(gname in games))
+    return null;
+  var game = games[gname];
+  function stopper(ev) {
+    stopgame(game);
+  }
+  return stopper;
+}
+
+function stopgame(game) {
+  if (!session.lcred)
+    return;
+  var stopmsg = {"key": session.lcred, "g": game.uname};
+  var req = new XMLHttpRequest();
+  req.onerror = errHandler;
+  req.onreadystatechange = function () {
+    if (req.readyState != 4 || req.status != 200) 
+      return;
+    var reply = JSON.parse(req.responseText);
+    if (reply.t == 'E') {
+      if (reply.c == 7)
+        message("That game has already stopped.");
+      else if (reply.c == 1) {
+        logout();
+        message("The server forgot about you, please log in again.", "warn");
+      }
+      else {
+        message("That game could not be stopped because: " + reply.s + 
+                "This might be a bug.", "warn");
+      }
+    }
+  }
+  req.open('POST', '/quit', true);
+  req.send(JSON.stringify(stopmsg));
+  return;
+}
+
 function wsStart(game) {
   var sockurl = "ws://" + window.location.host + "/play/" + game.uname;
   sockurl += "?key=" + session.lcred + "&w=80&h=24";
--- a/rlgwebd.js	Sun Jul 15 21:03:36 2012 -0700
+++ b/rlgwebd.js	Sun Jul 15 22:33:44 2012 -0700
@@ -896,6 +896,42 @@
   return;
 }
 
+/* Stops a running game if the request has the proper key. */
+function stopgame(res, formdata) {
+  if (!("key" in formdata) || !(formdata["key"] in logins)) {
+    sendError(res, 1);
+    return;
+  }
+  var pname = logins[formdata["key"]].name;
+  if (!("g" in formdata) || !(formdata["g"] in games)) {
+    sendError(res, 2, "No such game.");
+    return;
+  }
+  var gname = formdata["g"];
+  function checkback(err, fname) {
+    if (!fname) {
+      sendError(res, 7);
+      return;
+    }
+    var fullfile = path.join("/dgldir/inprogress-" + gname, fname);
+    fs.readFile(fullfile, "utf8", function(err, fdata) {
+      if (err) {
+        sendError(res, 7);
+        return;
+      }
+      var pid = parseInt(fdata.split('\n')[0], 10);
+      process.kill(pid, 'SIGHUP');
+      /* The response doesn't mean that the game is gone.  The only way
+       * to make sure a dgamelaunch-supervised game is over would be to
+       * poll fname until it disappears. */
+      res.writeHead(200, {'Content-Type': 'application/json'});
+      res.write(JSON.stringify({"t": "q"}));
+      res.end();
+    });
+  }
+  checkprogress(pname, games[gname], checkback, []);
+}
+
 function findClient(formdata, playersOnly) {
   if (typeof(formdata) != "object")
     return null;
@@ -1125,6 +1161,9 @@
       else if (target == "/watch") {
         watch(req, res, formdata);
       }
+      else if (target == "/quit") {
+        stopgame(res, formdata);
+      }
       else {
         res.writeHead(405, resheaders);
         res.end();