Mercurial > hg > rlgwebd
diff rlgwebd.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 | ad0a31e52007 |
children | d3e3d6b4016b |
line wrap: on
line diff
--- a/rlgwebd.js Tue May 15 16:26:28 2012 -0700 +++ b/rlgwebd.js Thu May 17 09:32:19 2012 -0700 @@ -43,7 +43,7 @@ * adds itself to the sessions dict. It currently assumes the user has * been authenticated. */ -function TermSession(game, user, files) { +function TermSession(game, user, files, dims) { /* First make sure starting the game will work. */ if (!(game in games)) { // TODO: throw an exception instead @@ -57,15 +57,33 @@ } /* Grab a spot in the sessions table. */ sessions[this.sessid] = this; + /* State for messaging. */ + this.nsend = 0; + this.nrecv = 0; + this.msgQ = [] + /* Set up the sizes. */ + this.w = Math.floor(Number(dims[1])); + if (!(this.w > 0 && this.w < 256)) + this.w = 80; + this.h = Math.floor(Number(dims[0])); + if (!(this.h > 0 && this.h < 256)) + this.h = 24; + /* Environment. */ + var childenv = {}; + for (var key in process.env) { + childenv[key] = process.env[key]; + } + childenv["PTYHELPER"] = String(this.h) + "x" + String(this.w); /* TODO handle tty-opening errors */ /* TODO make argument-finding into a method */ args = [games[game].path, "-n", user.toString()]; - this.child = child_process.spawn("/bin/ptyhelper", args); + this.child = child_process.spawn("/bin/ptyhelper", args, {"env": childenv}); var ss = this; this.alive = true; this.data = []; this.lock = files[0]; - fs.writeFile(this.lock, this.child.pid.toString() + '\n80\n24\n', "utf8"); + fs.writeFile(this.lock, this.child.pid.toString() + '\n' + this.w + '\n' + + this.h + '\n', "utf8"); this.record = fs.createWriteStream(files[1], { mode: 0664 }); /* END setup */ function ttyrec_chunk(buf) { @@ -206,6 +224,22 @@ return data; } +function getMsg(posttext) { + var jsonobj; + if (!posttext) + return {}; + try { + jsonobj = JSON.parse(posttext); + } + catch (e) { + if (e instanceof SyntaxError) + return {}; + } + if (typeof(jsonobj) != "object") + return {}; + return jsonobj; +} + function auth(username, password) { // Real authentication not implemented return true; @@ -224,9 +258,10 @@ sendError(res, 2, "Password not given."); return; } - var username = formdata["name"][0]; - var password = formdata["pw"][0]; - var gname = formdata["game"][0]; + var username = formdata["name"]; + var password = formdata["pw"]; + var gname = formdata["game"]; + var dims = [formdata["h"], formdata["w"]]; if (!(gname in games)) { sendError(res, 2, "No such game: " + gname); console.log("Request for nonexistant game \"" + gname + "\""); @@ -239,13 +274,15 @@ 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]); + var nsession = new TermSession(gname, username, [lockfile, ttyrec], 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': 'text/plain'}); - res.write("l1\n" + nsession.sessid + "\n"); + var reply = {"t": "l", "id": nsession.sessid, "w": nsession.w, "h": + nsession.h}; + res.write(JSON.stringify(reply)); res.end(); console.log("%s playing %s (key %s, pid %d)", username, gname, nsession.sessid, nsession.child.pid); @@ -309,14 +346,16 @@ cterm.close(); var resheaders = {'Content-Type': 'text/plain'}; res.writeHead(200, resheaders); - res.write("q1\n\n"); + res.write(JSON.stringify({"t": "q"})); res.end(); return; } function findTermSession(formdata) { + if (typeof(formdata) != "object") + return null; if ("id" in formdata) { - var sessid = formdata["id"][0]; + var sessid = formdata["id"]; if (sessid in sessions) { return sessions[sessid]; } @@ -370,22 +409,24 @@ function readFeed(res, term) { if (term) { + var reply = {}; var result = term.read(); + if (result == null) { + if (term.alive) + reply.t = "n"; + else + reply.t = "q"; + } + else { + reply.t = "d"; + reply.n = term.nsend++; + reply.d = result.toString("hex"); + } res.writeHead(200, { "Content-Type": "text/plain" }); - if (result == null) - resultstr = ""; - else - resultstr = result.toString("hex"); - if (result == null && !term.alive) { - /* Child has terminated and data is flushed. */ - res.write("q1\n\n"); - } - else - res.write("d" + resultstr.length.toString() + "\n" + resultstr + "\n"); + res.write(JSON.stringify(reply)); res.end(); } else { - //console.log("Where's the term?"); sendError(res, 1, null); } } @@ -395,14 +436,14 @@ function sendError(res, ecode, msg) { res.writeHead(200, { "Content-Type": "text/plain" }); - if (ecode < errorcodes.length && ecode > 0) { - var emsg = errorcodes[ecode]; - if (msg) - emsg += ": " + msg; - res.write("E" + ecode + '\n' + emsg + '\n'); - } - else - res.write("E0\nGeneric Error\n"); + var edict = {"t": "E"}; + if (!(ecode < errorcodes.length && ecode > 0)) + ecode = 0; + edict["c"] = ecode; + edict["s"] = errorcodes[ecode]; + if (msg) + edict["s"] += ": " + msg; + res.write(JSON.stringify(edict)); res.end(); } @@ -421,7 +462,8 @@ /* This will send the response once the whole request is here. */ function respond() { - formdata = getFormValues(reqbody); + //formdata = getFormValues(reqbody); + formdata = getMsg(reqbody); var target = url.parse(req.url).pathname; var cterm = findTermSession(formdata); /* First figure out if the client is POSTing to a command interface. */ @@ -431,18 +473,19 @@ sendError(res, 1, null); return; } - if ("quit" in formdata) { + if (formdata.t == "q") { /* The client wants to terminate the process. */ logout(cterm, res); } - else if (formdata["keys"]) { + else if (formdata.t == "d" && typeof(formdata.d) == "string") { /* process the keys */ - hexstr = formdata["keys"][0].replace(/[^0-9a-f]/gi, ""); + hexstr = formdata.d.replace(/[^0-9a-f]/gi, ""); if (hexstr.length % 2 != 0) { sendError(res, 2, "incomplete byte"); return; } keybuf = new Buffer(hexstr, "hex"); + /* TODO OoO correction */ cterm.write(keybuf); } readFeed(res, cterm);