diff rlgterm.js @ 16:ef6127ed6da3

RLGWeb: switch to JSON protocol. Port the JSON communication from WebTTY to RLGWeb. Fixing out-of-order messages is still not implemented on the server side. Terminal size is still hard-coded. Unused code is still lying around.
author John "Elwin" Edwards <elwin@sdf.org>
date Thu, 17 May 2012 09:32:19 -0700
parents 826a7ced69f8
children 188bbd857124
line wrap: on
line diff
--- a/rlgterm.js	Tue May 15 16:26:28 2012 -0700
+++ b/rlgterm.js	Thu May 17 09:32:19 2012 -0700
@@ -111,33 +111,67 @@
   return;
 }
 
+/* State for sending and receiving messages. */
+var nsend = 0; // The number of the next packet to send.
+var nrecv = 0; // The next packet expected.
+var msgQ = []; // Queue for out-of-order messages.
+
 /* Processes a message from the server, returning true or false if it was a 
- * data message with or without data, null if not data. */
+ * data message with or without data, null if not data.
+ * All non-special responseTexts should be handed directly to this function.
+ */
 function processMsg(msg) {
-  var msglines = msg.split("\n");
-  var havedata = null;
-  if (!msglines[0])
+  var msgDict;
+  var havedata = null; // eventual return value
+  try {
+    msgDict = JSON.parse(msg);
+  } catch (e) {
+    if (e instanceof SyntaxError)
+      return null;
+  }
+  if (!msgDict.t)
     return null;
-  if (msglines[0].charAt(0) == 'd') {
-    if (msglines[1]){
-      writeData(msglines[1]);
-      havedata = true;
+  else if (msgDict.t == "E") {
+    if (msgDict.c == 1) {
+      logout();
+    }
+    debug(1, "Server error: " + msgDict.s);
+  }
+  else if (msgDict.t == "n") {
+    havedata = false;
+  }
+  // A data message
+  else if (msgDict.t == "d"){
+    if (msgDict.n === nrecv) {
+      writeData(msgDict.d);
+      nrecv++;
+      /* Process anything in the queue that's now ready. */
+      var next;
+      while ((next = msgQ.shift()) !== undefined) {
+        writeData(next.d);
+        nrecv++;
+      }
+    }
+    else if (response.n > nrecv) {
+      /* The current message comes after one still missing.  Queue this one
+       * for later use. */
+      debug(1, "Got packet " + msgDict.n + ", expected " + nrecv);
+      msgQ[msgDict.n - nrecv - 1] = msgDict;
     }
     else {
-      havedata = false;
+      /* This message's number was encountered previously. */
+      debug(1, "Discarding packet " + msgDict.n + ", expected " + nrecv);
     }
+    havedata = true;
   }
-  else if (msglines[0] == "E1") {
-    logout();
+  else if (msgDict.t == "T") {
+    setTitle(msgDict.d);
   }
-  else if (msglines[0].charAt(0) == "T") {
-    setTitle(msglines[1]);
-  }
-  else if (msglines[0] == "q1") {
+  else if (msgDict.t == "q") {
     logout();
   }
   else {
-    debug(1, "Unrecognized server message " + msglines[0]);
+    debug(1, "Unrecognized server message " + msg);
   }
   return havedata;
 }
@@ -146,6 +180,7 @@
   if (termemu.sessid == null)
     return;
   var datareq = new XMLHttpRequest();
+  var msg = JSON.stringify({"id": termemu.sessid, "t": "n"});
   datareq.onreadystatechange = function () {
     if (datareq.readyState == 4 && datareq.status == 200) {
       var wasdata = processMsg(datareq.responseText);
@@ -159,7 +194,7 @@
     }
   };
   datareq.open('POST', '/feed', true);
-  datareq.send("id=" + termemu.sessid);
+  datareq.send(msg);
   return;
 }
 
@@ -174,10 +209,11 @@
 
 function sendback(str) {
   /* For responding to terminal queries. */
+  var msgDict = {"id": termemu.sessid, "t": "d", "n": nsend++, "d": str};
   var datareq = new XMLHttpRequest();
   datareq.onreadystatechange = postResponseHandler;
   datareq.open('POST', '/feed', true);
-  datareq.send("id=" + termemu.sessid + "&keys=" + str);
+  datareq.send(JSON.stringify(msgDict));
   return;
 }
 
@@ -219,12 +255,14 @@
     debug(1, "Ignoring keycode " + keynum);
     return;
   }
+  // Isn't this check redundant?
   if (termemu.sessid != null)
     ev.preventDefault();
   var datareq = new XMLHttpRequest();
+  var msgDict = {"id": termemu.sessid, "t": "d", "n": nsend++, "d": code};
   datareq.onreadystatechange = postResponseHandler;
   datareq.open('POST', '/feed', true);
-  datareq.send("id=" + termemu.sessid + "&keys=" + code);
+  datareq.send(JSON.stringify(msgDict));
   return;
 }
 
@@ -270,11 +308,11 @@
   }
   else
     return;
-  //writeData("Sending " + keystr);
   var datareq = new XMLHttpRequest();
+  var msgDict = {"id": termemu.sessid, "t": "d", "n": nsend++, "d": keystr};
   datareq.onreadystatechange = postResponseHandler;
   datareq.open('POST', '/feed', true);
-  datareq.send("id=" + termemu.sessid + "&keys=" + keystr);
+  datareq.send(JSON.stringify(msgDict));
   return;
 }
 
@@ -309,31 +347,34 @@
   ev.preventDefault();
   if (termemu.sessid != null)
     return;
-  var formname = document.getElementById("input_name").value;
-  var formpass = document.getElementById("input_pw").value;
-  var formgame = document.getElementById("input_game").value;
-  var formdata = "game=" + encodeURIComponent(formgame) + "&name=" + encodeURIComponent(formname) + "&pw=" + encodeURIComponent(formpass);
+  var loginmsg = {};
+  loginmsg["name"] = document.getElementById("input_name").value;
+  loginmsg["pw"] = document.getElementById("input_pw").value;
+  loginmsg["game"] = document.getElementById("input_game").value;
+  loginmsg["h"] = 24;
+  loginmsg["w"] = 80;
   var req = new XMLHttpRequest();
   req.onreadystatechange = function () {
-    if (req.readyState == 4 && req.status == 200) {
-      var datalines = req.responseText.split("\n");
-      if (datalines[0] == 'l1') {
-        /* Success */
-        termemu.sessid = datalines[1];
-	setTitle("Playing as " + formname);
-        debug(1, "Logged in with id " + termemu.sessid);
-        document.getElementById("loginform").style.display = "none";
-        getData();
-      }
-      else {
-        debug(1, "Could not start game: " + datalines[1]);
-        document.getElementById("input_name").value = "";
-        document.getElementById("input_pw").value = "";
-      }
+    if (req.readyState != 4 || req.status != 200) 
+      return;
+    var reply = JSON.parse(req.responseText);
+    if (reply.t == 'l') {
+      /* Success */
+      termemu.sessid = reply.id;
+      termemu.resize(reply.h, reply.w);
+      setTitle("Playing as " + loginmsg["name"]);
+      debug(1, "Logged in with id " + termemu.sessid);
+      document.getElementById("loginform").style.display = "none";
+      getData();
+    }
+    else if (reply.t == 'E') {
+      debug(1, "Could not start game: " + reply.s);
+      document.getElementById("input_name").value = "";
+      document.getElementById("input_pw").value = "";
     }
   };
   req.open('POST', '/login', true);
-  req.send(formdata);
+  req.send(JSON.stringify(loginmsg));
   return;
 }
 
@@ -342,6 +383,9 @@
     return;
   termemu.sessid = null;
   setTitle("Game over.");
+  nsend = 0;
+  nrecv = 0;
+  msgQ = [];
   document.getElementById("loginform").style.display = "block";
   return;
 }
@@ -355,7 +399,7 @@
     }
   };
   req.open('POST', '/feed', true);
-  req.send("id=" + termemu.sessid + "&quit=quit");
+  req.send(JSON.stringify({"id": termemu.sessid, "t": "q"}));
   return;
 }