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 } |