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