Mercurial > hg > rlgwebd
comparison rlgwebd.js @ 185:bbfda4a4eb7f
Finish moving DglSession methods into the prototype.
| author | John "Elwin" Edwards |
|---|---|
| date | Tue, 20 Jan 2015 10:17:05 -0500 |
| parents | ecedc6f7e4ac |
| children | 11b7baed2e21 |
comparison
equal
deleted
inserted
replaced
| 184:ecedc6f7e4ac | 185:bbfda4a4eb7f |
|---|---|
| 268 delete sessions[tag]; | 268 delete sessions[tag]; |
| 269 tslog("Game %s ended.", tag); | 269 tslog("Game %s ended.", tag); |
| 270 }; | 270 }; |
| 271 | 271 |
| 272 function DglSession(filename) { | 272 function DglSession(filename) { |
| 273 var ss = this; | |
| 274 BaseGame.call(this); | 273 BaseGame.call(this); |
| 275 var pathcoms = filename.split('/'); | 274 var pathcoms = filename.split('/'); |
| 276 this.gname = pathcoms[pathcoms.length - 2]; | 275 this.gname = pathcoms[pathcoms.length - 2]; |
| 277 if (!(this.gname in games)) { | 276 if (!(this.gname in games)) { |
| 278 ss.emit('open', false); | 277 this.emit('open', false); |
| 279 return; | 278 return; |
| 280 } | 279 } |
| 281 var basename = pathcoms[pathcoms.length - 1]; | 280 var basename = pathcoms[pathcoms.length - 1]; |
| 282 var firstsep = basename.indexOf(':'); | 281 var firstsep = basename.indexOf(':'); |
| 283 this.pname = basename.slice(0, firstsep); | 282 this.pname = basename.slice(0, firstsep); |
| 285 this.ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname, fname); | 284 this.ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname, fname); |
| 286 /* Flag to prevent multiple handlers from reading simultaneously and | 285 /* Flag to prevent multiple handlers from reading simultaneously and |
| 287 * getting into a race. */ | 286 * getting into a race. */ |
| 288 this.reading = false; | 287 this.reading = false; |
| 289 this.rpos = 0; | 288 this.rpos = 0; |
| 290 this.readchunk = function () { | 289 fs.readFile(filename, {encoding: "utf8"}, (function (err, data) { |
| 291 if (this.reading) | 290 if (err) { |
| 291 this.emit('open', false); | |
| 292 return; | 292 return; |
| 293 this.reading = true; | |
| 294 var header = new Buffer(12); | |
| 295 fs.read(ss.fd, header, 0, 12, ss.rpos, function (err, n, buf) { | |
| 296 /* Stop recursion if end of file has been reached. */ | |
| 297 if (err || n < 12) { | |
| 298 if (!err && n > 0) { | |
| 299 tslog("DGL %s: expected 12-byte header, got %d", ss.tag(), n); | |
| 300 } | |
| 301 ss.reading = false; | |
| 302 return; | |
| 303 } | |
| 304 ss.rpos += 12; | |
| 305 /* Update timestamp, to within 1 second. */ | |
| 306 ss.lasttime = new Date(1000 * buf.readUInt32LE(0)); | |
| 307 var datalen = buf.readUInt32LE(8); | |
| 308 if (datalen > 16384) { | |
| 309 // Something is probably wrong... | |
| 310 tslog("DGL %s: looking for %d bytes", ss.tag(), datalen); | |
| 311 } | |
| 312 var databuf = new Buffer(datalen); | |
| 313 fs.read(ss.fd, databuf, 0, datalen, ss.rpos, function (err, n, buf) { | |
| 314 if (err || n < datalen) { | |
| 315 /* Next time, read the header again. */ | |
| 316 ss.rpos -= 12; | |
| 317 ss.reading = false; | |
| 318 tslog("DGL %s: expected %d bytes, got %d", ss.tag(), datalen, n); | |
| 319 return; | |
| 320 } | |
| 321 ss.rpos += n; | |
| 322 ss.reading = false; | |
| 323 /* Process the data */ | |
| 324 ss.framepush(buf); | |
| 325 var wmsg = JSON.stringify({"t": "d", "d": buf.toString("hex")}); | |
| 326 for (var i = 0; i < ss.watchers.length; i++) { | |
| 327 if (ss.watchers[i].connected) | |
| 328 ss.watchers[i].sendUTF(wmsg); | |
| 329 } | |
| 330 ss.emit("data", buf); | |
| 331 //tslog("DGL %s: %d bytes", ss.tag(), buf.length); | |
| 332 /* Recurse. */ | |
| 333 ss.readchunk(); | |
| 334 }); | |
| 335 }); | |
| 336 }; | |
| 337 fs.readFile(filename, {encoding: "utf8"}, function (err, data) { | |
| 338 if (err) { | |
| 339 ss.emit('open', false); | |
| 340 return; | |
| 341 } | 293 } |
| 342 var lines = data.split('\n'); | 294 var lines = data.split('\n'); |
| 343 ss.h = Number(lines[1]); | 295 this.h = Number(lines[1]); |
| 344 ss.w = Number(lines[2]); | 296 this.w = Number(lines[2]); |
| 345 fs.open(ss.ttyrec, "r", function(err, fd) { | 297 fs.open(this.ttyrec, "r", (function (err, fd) { |
| 346 if (err) { | 298 if (err) { |
| 347 ss.emit('open', false); | 299 this.emit('open', false); |
| 348 } | 300 } |
| 349 else { | 301 else { |
| 350 ss.fd = fd; | 302 this.fd = fd; |
| 351 ss.emit('open', true); | 303 this.emit('open', true); |
| 352 tslog("DGL %s: open", ss.tag()); | 304 tslog("DGL %s: open", this.tag()); |
| 353 gamemux.emit('begin', ss.gname, ss.pname, 'dgl'); | 305 gamemux.emit('begin', this.gname, this.pname, 'dgl'); |
| 354 ss.readchunk(); | 306 this.startchunk(); |
| 355 ss.recwatcher = fs.watch(ss.ttyrec, function (ev, finame) { | 307 this.recwatcher = fs.watch(this.ttyrec, this.notifier.bind(this)); |
| 356 if (ev == "change") | 308 } |
| 357 ss.readchunk(); | 309 }).bind(this)); |
| 358 }); | 310 }).bind(this)); |
| 359 } | |
| 360 }); | |
| 361 }); | |
| 362 this.close = function () { | |
| 363 this.recwatcher.close() | |
| 364 /* Ensure all data is handled before quitting. */ | |
| 365 this.readchunk(); | |
| 366 var connlist = this.watchers; | |
| 367 this.watchers = []; | |
| 368 for (var i = 0; i < connlist.length; i++) { | |
| 369 if (connlist[i].connected) | |
| 370 connlist[i].close(); | |
| 371 } | |
| 372 fs.close(this.fd); | |
| 373 this.emit("close"); | |
| 374 gamemux.emit('end', this.gname, this.pname); | |
| 375 tslog("DGL %s: closed", ss.tag()); | |
| 376 }; | |
| 377 } | 311 } |
| 378 DglSession.prototype = new BaseGame(); | 312 DglSession.prototype = new BaseGame(); |
| 313 | |
| 314 /* 3 functions to get data from the ttyrec file. */ | |
| 315 DglSession.prototype.startchunk = function () { | |
| 316 if (this.reading) | |
| 317 return; | |
| 318 this.reading = true; | |
| 319 var header = new Buffer(12); | |
| 320 fs.read(this.fd, header, 0, 12, this.rpos, this.datachunk.bind(this)); | |
| 321 }; | |
| 322 | |
| 323 DglSession.prototype.datachunk = function (err, n, buf) { | |
| 324 /* Stop recursion if end of file has been reached. */ | |
| 325 if (err || n < 12) { | |
| 326 if (!err && n > 0) { | |
| 327 tslog("DGL %s: expected 12-byte header, got %d", this.tag(), n); | |
| 328 } | |
| 329 this.reading = false; | |
| 330 return; | |
| 331 } | |
| 332 this.rpos += 12; | |
| 333 /* Update timestamp, to within 1 second. */ | |
| 334 this.lasttime = new Date(1000 * buf.readUInt32LE(0)); | |
| 335 var datalen = buf.readUInt32LE(8); | |
| 336 if (datalen > 16384) { | |
| 337 // Something is probably wrong... | |
| 338 tslog("DGL %s: looking for %d bytes", this.tag(), datalen); | |
| 339 } | |
| 340 var databuf = new Buffer(datalen); | |
| 341 fs.read(this.fd, databuf, 0, datalen, this.rpos, this.handledata.bind(this)); | |
| 342 }; | |
| 343 | |
| 344 DglSession.prototype.handledata = function (err, n, buf) { | |
| 345 if (err || n < buf.length) { | |
| 346 /* Next time, read the header again. */ | |
| 347 this.rpos -= 12; | |
| 348 this.reading = false; | |
| 349 tslog("DGL %s: expected %d bytes, got %d", this.tag(), buf.length, n); | |
| 350 return; | |
| 351 } | |
| 352 this.rpos += n; | |
| 353 this.reading = false; | |
| 354 /* Process the data */ | |
| 355 this.framepush(buf); | |
| 356 var wmsg = JSON.stringify({"t": "d", "d": buf.toString("hex")}); | |
| 357 for (var i = 0; i < this.watchers.length; i++) { | |
| 358 if (this.watchers[i].connected) | |
| 359 this.watchers[i].sendUTF(wmsg); | |
| 360 } | |
| 361 this.emit("data", buf); | |
| 362 /* Recurse. */ | |
| 363 this.startchunk(); | |
| 364 }; | |
| 365 | |
| 366 /* Handles events from the ttyrec file watcher. */ | |
| 367 DglSession.prototype.notifier = function (ev, finame) { | |
| 368 if (ev == "change") | |
| 369 this.startchunk(); | |
| 370 /* If another kind of event appears, something strange happened. */ | |
| 371 }; | |
| 372 | |
| 373 DglSession.prototype.close = function () { | |
| 374 this.recwatcher.close(); | |
| 375 /* Ensure all data is handled before quitting. */ | |
| 376 this.startchunk(); | |
| 377 var connlist = this.watchers; | |
| 378 this.watchers = []; | |
| 379 for (var i = 0; i < connlist.length; i++) { | |
| 380 if (connlist[i].connected) | |
| 381 connlist[i].close(); | |
| 382 } | |
| 383 fs.close(this.fd); | |
| 384 this.emit("close"); | |
| 385 gamemux.emit('end', this.gname, this.pname); | |
| 386 tslog("DGL %s: closed", this.tag()); | |
| 387 }; | |
| 379 | 388 |
| 380 function wsStartGame(wsReq) { | 389 function wsStartGame(wsReq) { |
| 381 var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/); | 390 var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/); |
| 382 if (!playmatch[1] || !(playmatch[1] in games)) { | 391 if (!playmatch[1] || !(playmatch[1] in games)) { |
| 383 wsReq.reject(404, errorcodes[2]); | 392 wsReq.reject(404, errorcodes[2]); |
