RLG-Web: begin converting to WebSockets.

Use WebSockets for watching, if the browser supports it.  Functionality
is not complete yet.
This commit is contained in:
John "Elwin" Edwards 2012-07-12 22:16:15 -07:00
parent e143ac7d20
commit aee00a29d5
2 changed files with 88 additions and 1 deletions

View file

@ -82,7 +82,9 @@ var session = {
lname: null,
lcred: null,
/* Whether the game is being played or just watched. */
playing: false
playing: false,
/* WebSocket for communication */
sock: null
};
/* The interval ID for checking the status of current games. */
@ -655,6 +657,10 @@ function startgame(game) {
function startwatching(gamenumber) {
if (session.id != null)
return;
if (WebSocket) {
wsWatch(gamenumber);
return;
}
var wmsg = {"n": Number(gamenumber)};
var req = new XMLHttpRequest();
req.onerror = errHandler;
@ -692,6 +698,27 @@ function makeWatcher(n) {
return watcher;
}
function wsWatch(gamenumber) {
var sockurl = "ws://localhost:8080/watch/" + String(gamenumber);
var ws = new WebSocket(sockurl);
ws.onopen = function (event) {
session.id = true;
session.sock = ws;
message("You are now watching game #" + gamenumber + ".");
setmode("watch");
};
ws.onmessage = function (event) {
var msgObject = JSON.parse(event.data);
if (msgObject.t == 'd') {
writeData(msgObject.d);
}
};
ws.onclose = function (event) {
session.sock = null;
gameover();
};
}
function formreg(ev) {
ev.preventDefault();
if (session.id != null)
@ -775,6 +802,10 @@ function logout() {
function stop() {
if (!session.id)
return;
if (session.sock) {
session.sock.close();
return;
}
var req = new XMLHttpRequest();
req.onerror = errHandler;
req.onreadystatechange = function () {

View file

@ -11,6 +11,7 @@ var events = require('events');
var child_process = require('child_process');
var daemon = require(path.join(localModules, "daemon"));
var pty = require(path.join(localModules, "pty.js"));
var WebSocketServer = require(path.join(localModules, "websocket")).server;
/* Configuration variables */
// These first two files are NOT in the chroot.
@ -130,6 +131,8 @@ function TermSession(game, lkey, dims, handlers) {
* with a complete screen. */
this.framebuf = new Buffer(1024);
this.frameoff = 0;
/* List of WebSockets watching the game. */
this.watchsocks = [];
logins[lkey].sessions.push(this.sessid);
/* END setup */
function ttyrec_chunk(datastr) {
@ -168,6 +171,22 @@ function TermSession(game, lkey, dims, handlers) {
this.write = function(data) {
this.term.write(data);
};
// WebSocket watchers.
this.addWS = function (conn) {
this.watchsocks.push(conn);
};
this.removeWS = function (conn) {
var i = this.watchsocks.indexOf(conn);
if (i >= 0) {
if (conn.connected)
conn.close();
this.watchsocks.splice(i, 1);
return true;
}
else
return false;
};
// Teardown.
this.term.on("exit", function () {
fs.unlink(ss.lock);
ss.record.end();
@ -354,6 +373,27 @@ function Player(gamename, lkey, dims, callback) {
this.session = new TermSession(gamename, lkey, dims, handlers);
}
// Also known as WebSocketAndTermSessionClosureGlueFactory
function wsWatcher(conn, session) {
var ss = this; // is this even needed?
var dataH = function(buf) {
conn.sendUTF(JSON.stringify({"t": "d", "d": buf.toString("hex")}));
};
var exitH = function() {
if (conn.connected)
conn.close();
}
session.on('data', dataH);
session.on('exit', exitH);
conn.on('close', function(code, desc) {
session.removeListener('data', dataH);
session.removeListener('exit', exitH);
tslog("A WebSocket watcher has left game %d", session.sessid);
});
conn.sendUTF(JSON.stringify({"t": "d",
"d": session.framebuf.toString("hex", 0, session.frameoff)}));
}
/* Some functions which check whether a player is currently playing or
* has a saved game. Maybe someday they will provide information on
* the game. */
@ -1029,6 +1069,18 @@ function webHandler(req, res) {
}
function wsHandler(wsRequest) {
var urlmatch = wsRequest.resource.match(/^\/watch\/([0-9]*)$/);
if (urlmatch !== null && urlmatch[1] && Number(urlmatch[1]) in sessions) {
var tsession = sessions[Number(urlmatch[1])];
var conn = wsRequest.accept(null, wsRequest.origin);
new wsWatcher(conn, tsession);
tslog("Game %d is being watched via WebSockets", tsession.sessid);
}
else
wsRequest.reject(404, errorcodes[7]);
}
function shutdown () {
httpServer.close();
httpServer.removeAllListeners('request');
@ -1066,6 +1118,7 @@ if (process.getuid() != 0) {
}
var httpServer; // declare here so shutdown() can find it
var wsServer;
/* This could be nonblocking, but nothing else can start yet anyway. */
if (fs.existsSync(ctlsocket)) {
@ -1106,5 +1159,8 @@ ctlServer.listen(ctlsocket, function () {
httpServer.listen(httpPort);
tslog('rlgwebd running on port %d', httpPort);
setInterval(reaper, playtimeout / 4);
wsServer = new WebSocketServer({"httpServer": httpServer});
wsServer.on("request", wsHandler);
tslog('WebSockets are online');
});