RLGWebD: fix simultaneous watcher bugs.

WebSockets should now only receive the intended data, no matter how
many of them there are or what they are doing.  They should...
This commit is contained in:
John "Elwin" Edwards 2015-01-10 18:54:55 -05:00
parent 6373e70361
commit 60b83c4944

View file

@ -125,6 +125,8 @@ function TermSession(gname, pname, wsReq) {
this.framebuf = new Buffer(1024);
this.frameoff = 0;
this.playerconn = wsReq.accept(null, wsReq.origin);
/* Array for watcher connections. */
this.watchers = [];
/* END setup */
function ttyrec_chunk(datastr) {
ss.lasttime = new Date();
@ -138,9 +140,13 @@ function TermSession(gname, pname, wsReq) {
ss.record.write(chunk);
ss.framepush(buf);
/* Send to the player. */
var msg = {"t": "d", "d": buf.toString("hex")};
ss.playerconn.sendUTF(JSON.stringify(msg));
/* For the benefit of watchers. */
var msg = JSON.stringify({"t": "d", "d": buf.toString("hex")});
ss.playerconn.sendUTF(msg);
/* Send to any watchers. */
for (var i = 0; i < ss.watchers.length; i++) {
if (ss.watchers[i].connected)
ss.watchers[i].sendUTF(msg);
}
ss.emit('data', buf);
}
this.term.on("data", ttyrec_chunk);
@ -174,6 +180,12 @@ function TermSession(gname, pname, wsReq) {
var tag = ss.tag();
fs.unlink(ss.lock);
ss.record.end();
var watchsocks = ss.watchers;
ss.watchers = [];
for (var i = 0; i < watchsocks.length; i++) {
if (watchsocks[i].connected)
watchsocks[i].close();
}
if (ss.playerconn.connected) {
ss.playerconn.sendUTF(JSON.stringify({"t": "q"}));
ss.playerconn.close();
@ -207,6 +219,25 @@ function TermSession(gname, pname, wsReq) {
}
this.playerconn.on('message', messageH);
this.playerconn.on('close', this.close);
/* To attach a watcher. */
this.attach = function (wsReq) {
var conn = wsReq.accept(null, wsReq.origin);
conn.sendUTF(JSON.stringify({
"t": "w", "w": this.w, "h": this.h, "p": this.pname,
"g": this.game.uname
}));
conn.sendUTF(JSON.stringify({"t": "d",
"d": this.framebuf.toString("hex", 0, this.frameoff)}));
conn.on('close', function () {
/* 'this' is the connection when triggered */
var n = ss.watchers.indexOf(this);
if (n >= 0) {
ss.watchers.splice(n, 1);
tslog("A WebSocket watcher has left game %s", ss.tag());
}
});
this.watchers.push(conn);
};
}
TermSession.prototype = new events.EventEmitter();
@ -316,32 +347,6 @@ function DglSession(filename) {
}
DglSession.prototype = new events.EventEmitter();
// 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);
if (session.tag() in sessions)
tslog("A WebSocket watcher has left game %s", session.tag());
});
conn.sendUTF(JSON.stringify({
"t": "w", "w": session.w, "h": session.h,
"p": session.pname, "g": session.game.uname
}));
conn.sendUTF(JSON.stringify({"t": "d",
"d": session.framebuf.toString("hex", 0, session.frameoff)}));
}
function wsStartGame(wsReq) {
var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/);
if (!playmatch[1] || !(playmatch[1] in games)) {
@ -1009,8 +1014,7 @@ function wsHandler(wsRequest) {
return;
}
var tsession = sessions[watchmatch[1]];
var conn = wsRequest.accept(null, wsRequest.origin);
new wsWatcher(conn, tsession);
tsession.attach(wsRequest);
tslog("Game %s is being watched via WebSockets", tsession.tag());
}
else if (playmatch !== null) {