Mercurial > hg > rlgwebd
comparison rlgwebd.js @ 164:3a97e4ee50f0
rlgwebd.js: read ttyrecs created by dgamelaunch.
TTYREC files created by dgamelaunch are tracked by DglSession objects,
as a first step toward making them watchable.
| author | John "Elwin" Edwards |
|---|---|
| date | Tue, 06 Jan 2015 16:59:12 -0500 |
| parents | 0f6da35b27a0 |
| children | 59e62710cbb5 |
comparison
equal
deleted
inserted
replaced
| 163:0f6da35b27a0 | 164:3a97e4ee50f0 |
|---|---|
| 189 this.term.kill('SIGHUP'); | 189 this.term.kill('SIGHUP'); |
| 190 }; | 190 }; |
| 191 } | 191 } |
| 192 TermSession.prototype = new events.EventEmitter(); | 192 TermSession.prototype = new events.EventEmitter(); |
| 193 | 193 |
| 194 function DglSession(filename) { | |
| 195 var ss = this; | |
| 196 events.EventEmitter.call(this); | |
| 197 var pathcoms = filename.split('/'); | |
| 198 this.gname = pathcoms[pathcoms.length - 2]; | |
| 199 if (!(this.gname in games)) { | |
| 200 ss.emit('open', false); | |
| 201 return; | |
| 202 } | |
| 203 var basename = pathcoms[pathcoms.length - 1]; | |
| 204 var firstsep = basename.indexOf(':'); | |
| 205 this.pname = basename.slice(0, firstsep); | |
| 206 var fname = basename.slice(firstsep + 1); | |
| 207 this.ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname, fname); | |
| 208 this.framebuf = new Buffer(1024); | |
| 209 this.frameoff = 0; | |
| 210 this.framepush = function(chunk) { | |
| 211 /* If this chunk resets the screen, discard what preceded it. */ | |
| 212 var cgame = games[this.gname]; | |
| 213 if (bufncmp(chunk, cgame.clear, cgame.clear.length)) { | |
| 214 tslog("DGL %s: clearing frame", ss.tag()); | |
| 215 this.framebuf = new Buffer(1024); | |
| 216 this.frameoff = 0; | |
| 217 } | |
| 218 /* Make sure there's space. */ | |
| 219 while (this.framebuf.length < chunk.length + this.frameoff) { | |
| 220 var nbuf = new Buffer(this.framebuf.length * 2); | |
| 221 this.framebuf.copy(nbuf, 0, 0, this.frameoff); | |
| 222 this.framebuf = nbuf; | |
| 223 if (this.framebuf.length > 65536) { | |
| 224 tslog("Warning: DGL %s frame buffer at %d bytes", this.tag(), | |
| 225 this.framebuf.length); | |
| 226 } | |
| 227 } | |
| 228 chunk.copy(this.framebuf, this.frameoff); | |
| 229 this.frameoff += chunk.length; | |
| 230 }; | |
| 231 this.readchunk = function () { | |
| 232 var header = new Buffer(12); | |
| 233 fs.read(ss.fd, header, 0, 12, null, function (err, n, buf) { | |
| 234 /* Stop recursion if end of file has been reached. */ | |
| 235 if (err || n < 12) | |
| 236 return; | |
| 237 var datalen = buf.readUInt32LE(8); | |
| 238 //tslog("Allocating %d bytes", datalen); | |
| 239 var databuf = new Buffer(datalen); | |
| 240 fs.read(ss.fd, databuf, 0, datalen, null, function (err, n, buf) { | |
| 241 if (err || n < datalen) | |
| 242 return; | |
| 243 /* Process the data */ | |
| 244 ss.framepush(buf); | |
| 245 ss.emit("data", buf); | |
| 246 tslog("DGL %s: %d bytes", ss.tag(), buf.length); | |
| 247 /* Recurse. */ | |
| 248 ss.readchunk(); | |
| 249 }); | |
| 250 }); | |
| 251 }; | |
| 252 fs.readFile(filename, {encoding: "utf8"}, function (err, data) { | |
| 253 if (err) { | |
| 254 ss.emit('open', false); | |
| 255 return; | |
| 256 } | |
| 257 var lines = data.split('\n'); | |
| 258 ss.h = Number(lines[1]); | |
| 259 ss.w = Number(lines[2]); | |
| 260 fs.open(ss.ttyrec, "r", function(err, fd) { | |
| 261 if (err) { | |
| 262 ss.emit('open', false); | |
| 263 } | |
| 264 else { | |
| 265 ss.fd = fd; | |
| 266 ss.emit('open', true); | |
| 267 tslog("DGL %s: open", ss.tag()); | |
| 268 ss.readchunk(); | |
| 269 ss.watcher = fs.watch(ss.ttyrec, function (ev, finame) { | |
| 270 if (ev == "change") | |
| 271 ss.readchunk(); | |
| 272 }); | |
| 273 } | |
| 274 }); | |
| 275 }); | |
| 276 this.tag = function () { | |
| 277 return this.gname + "/" + this.pname; | |
| 278 }; | |
| 279 this.close = function () { | |
| 280 this.watcher.close() | |
| 281 fs.close(this.fd); | |
| 282 this.emit("close"); | |
| 283 tslog("DGL %s: closed", ss.tag()); | |
| 284 }; | |
| 285 } | |
| 286 DglSession.prototype = new events.EventEmitter(); | |
| 287 | |
| 194 // Also known as WebSocketAndTermSessionClosureGlueFactory | 288 // Also known as WebSocketAndTermSessionClosureGlueFactory |
| 195 function wsWatcher(conn, session) { | 289 function wsWatcher(conn, session) { |
| 196 var ss = this; // is this even needed? | 290 var ss = this; // is this even needed? |
| 197 var dataH = function(buf) { | 291 var dataH = function(buf) { |
| 198 conn.sendUTF(JSON.stringify({"t": "d", "d": buf.toString("hex")})); | 292 conn.sendUTF(JSON.stringify({"t": "d", "d": buf.toString("hex")})); |
| 629 var gname = matchresult[1]; | 723 var gname = matchresult[1]; |
| 630 var pname = matchresult[2]; | 724 var pname = matchresult[2]; |
| 631 var tag = gname + "/" + pname; | 725 var tag = gname + "/" + pname; |
| 632 if (chunk[0] == "E") { | 726 if (chunk[0] == "E") { |
| 633 tslog("DGL: %s is playing %s: %s", pname, gname, fname) | 727 tslog("DGL: %s is playing %s: %s", pname, gname, fname) |
| 634 dglgames[tag] = fname; | 728 dglgames[tag] = new DglSession(fname); |
| 635 } | 729 } |
| 636 else if (chunk[0] == "C") { | 730 else if (chunk[0] == "C") { |
| 637 tslog("DGL: %s started playing %s: %s", pname, gname, fname) | 731 tslog("DGL: %s started playing %s: %s", pname, gname, fname) |
| 638 dglgames[tag] = fname; | 732 dglgames[tag] = new DglSession(fname); |
| 639 } | 733 } |
| 640 else if (chunk[0] == "D") { | 734 else if (chunk[0] == "D") { |
| 641 tslog("DGL: %s finished playing %s: %s", pname, gname, fname) | 735 tslog("DGL: %s finished playing %s: %s", pname, gname, fname) |
| 736 dglgames[tag].close(); | |
| 642 delete dglgames[tag]; | 737 delete dglgames[tag]; |
| 643 } | 738 } |
| 644 else { | 739 else { |
| 645 tslog("Watcher says: %s", chunk) | 740 tslog("Watcher says: %s", chunk) |
| 646 } | 741 } |
