# HG changeset patch # User John "Elwin" Edwards # Date 1420934095 18000 # Node ID 671bed5039aa9dfa4fa3efb383a080496e8cd9e0 # Parent 50e4c9feeac2368d53a9ca08d8b9e108c698b430 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... diff -r 50e4c9feeac2 -r 671bed5039aa rlgwebd.js --- a/rlgwebd.js Fri Jan 09 13:06:41 2015 -0500 +++ b/rlgwebd.js Sat Jan 10 18:54:55 2015 -0500 @@ -125,6 +125,8 @@ 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 @@ 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 @@ 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 @@ } 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 @@ } 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 @@ 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) {