RLG-Web server: add playing through WebSockets.

Games can be played with a WebSocket connection to
/play/<game>?key=<loginkey>&w=<cols>&h=<rows>
This commit is contained in:
John "Elwin" Edwards 2012-07-15 09:04:39 -07:00
parent 185ea6a9ef
commit d11eb5e22a

View file

@ -182,6 +182,7 @@ function TermSession(game, lkey, dims, handlers) {
gamemux.emit('end', id); gamemux.emit('end', id);
}); });
this.close = function () { this.close = function () {
if (this.sessid in sessions)
this.term.kill('SIGHUP'); this.term.kill('SIGHUP');
}; };
} }
@ -385,6 +386,93 @@ function wsWatcher(conn, session) {
"d": session.framebuf.toString("hex", 0, session.frameoff)})); "d": session.framebuf.toString("hex", 0, session.frameoff)}));
} }
function wsPlay(wsReq, game, lkey, dims) {
var conn;
var session;
/* Listeners on the WebSocket */
function messageH(message) {
var parsedMsg = getMsgWS(message);
if (parsedMsg.t == 'q') {
session.close();
}
else if (parsedMsg.t == 'd') {
var hexstr = parsedMsg.d.replace(/[^0-9a-f]/gi, "");
if (hexstr.length % 2 != 0) {
hexstr = hexstr.slice(0, -1);
}
var keybuf = new Buffer(hexstr, "hex");
session.write(keybuf);
}
}
function closeH() {
session.close();
}
/* These listen on the TermSession. */
function openH(success, id) {
if (success) {
var reply = {"t": "s", "id": id, "w": sessions[id].w, "h":
sessions[id].h, "p": sessions[id].pname, "g": game};
conn = wsReq.accept(null, wsReq.origin);
conn.sendUTF(JSON.stringify(reply));
conn.on('message', messageH);
conn.on('close', closeH);
}
else {
wsReq.reject(500, errorcodes[5]);
tslog("Unable to allocate TTY for %s", game);
}
}
function dataH(chunk) {
var msg = {};
msg.t = "d";
msg.d = chunk.toString("hex");
conn.sendUTF(JSON.stringify(msg));
}
function exitH() {
if (conn.connected)
conn.sendUTF(JSON.stringify({"t": "q"}));
conn.close();
session.removeListener('open', openH);
session.removeListener('data', dataH);
session.removeListener('exit', exitH);
}
var handlers = {'open': openH, 'data': dataH, 'exit': exitH};
session = new TermSession(game, lkey, dims, handlers);
}
function wsStart(wsReq) {
var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/);
if (!playmatch[1] || !(playmatch[1] in games)) {
wsReq.reject(404, errorcodes[2]);
return;
}
var gname = playmatch[1];
if (!allowlogin) {
wsReq.reject(404, errorcodes[6]);
return;
}
if (!("key" in wsReq.resourceURL.query)) {
wsReq.reject(404, "No key given.");
return;
}
var lkey = wsReq.resourceURL.query["key"];
if (!(lkey in logins)) {
wsReq.reject(404, errorcodes[1]);
return;
}
var pname = logins[lkey].name;
var dims = [wsReq.resourceURL.query.h, wsReq.resourceURL.query.w];
function progcallback(err, fname) {
if (fname) {
wsReq.reject(404, errorcodes[4]);
tslog("%s is already playing %s", pname, gname);
}
else
wsPlay(wsReq, gname, lkey, dims);
};
checkprogress(pname, games[gname], progcallback, []);
}
/* Some functions which check whether a player is currently playing or /* Some functions which check whether a player is currently playing or
* has a saved game. Maybe someday they will provide information on * has a saved game. Maybe someday they will provide information on
* the game. */ * the game. */
@ -530,6 +618,12 @@ function getMsg(posttext) {
return jsonobj; return jsonobj;
} }
function getMsgWS(msgObj) {
if (msgObj.type != "utf8")
return {};
return getMsg(msgObj.utf8Data);
}
function reaper() { function reaper() {
var now = new Date(); var now = new Date();
function reapcheck(session) { function reapcheck(session) {
@ -1007,12 +1101,12 @@ function webHandler(req, res) {
return; return;
} }
/* process the keys */ /* process the keys */
hexstr = formdata.d.replace(/[^0-9a-f]/gi, ""); var hexstr = formdata.d.replace(/[^0-9a-f]/gi, "");
if (hexstr.length % 2 != 0) { if (hexstr.length % 2 != 0) {
sendError(res, 2, "incomplete byte", true); sendError(res, 2, "incomplete byte", true);
return; return;
} }
keybuf = new Buffer(hexstr, "hex"); var keybuf = new Buffer(hexstr, "hex");
client.write(keybuf, formdata.n); client.write(keybuf, formdata.n);
} }
readFeed(client, res); readFeed(client, res);
@ -1066,6 +1160,7 @@ function webHandler(req, res) {
function wsHandler(wsRequest) { function wsHandler(wsRequest) {
var watchmatch = wsRequest.resource.match(/^\/watch\/([0-9]*)$/); var watchmatch = wsRequest.resource.match(/^\/watch\/([0-9]*)$/);
var playmatch = wsRequest.resource.match(/^\/play\//);
if (watchmatch !== null) { if (watchmatch !== null) {
if (watchmatch[1] && Number(watchmatch[1]) in sessions) { if (watchmatch[1] && Number(watchmatch[1]) in sessions) {
var tsession = sessions[Number(watchmatch[1])]; var tsession = sessions[Number(watchmatch[1])];
@ -1076,7 +1171,10 @@ function wsHandler(wsRequest) {
else else
wsRequest.reject(404, errorcodes[7]); wsRequest.reject(404, errorcodes[7]);
} }
else if (wsRequest.resource == "/status") { else if (playmatch !== null) {
wsStart(wsRequest);
}
else if (wsRequest.resourceURL.pathname == "/status") {
var conn = wsRequest.accept(null, wsRequest.origin); var conn = wsRequest.accept(null, wsRequest.origin);
var tell = function () { var tell = function () {
getStatus(function (info) { getStatus(function (info) {