Move TermSession and DglSession common code into a base class.
This commit is contained in:
parent
a2bb3fe97d
commit
677d739bed
1 changed files with 64 additions and 104 deletions
168
rlgwebd.js
168
rlgwebd.js
|
|
@ -66,7 +66,66 @@ var dglgames = {};
|
|||
var allowlogin = true;
|
||||
var gamemux = new events.EventEmitter();
|
||||
|
||||
/* TODO move TermSession and DglSession methods into the prototypes. */
|
||||
/* A base class. TermSession and DglSession inherit from it. */
|
||||
function BaseGame() {
|
||||
/* Games subclass EventEmitter, though there are few listeners. */
|
||||
events.EventEmitter.call(this);
|
||||
/* Array of watching WebSockets. */
|
||||
this.watchers = [];
|
||||
/* replaybuf holds the output since the last screen clear, so watchers can
|
||||
* begin with a complete screen. replaylen is the number of bytes stored. */
|
||||
this.replaybuf = new Buffer(1024);
|
||||
this.replaylen = 0;
|
||||
/* Time of last activity. */
|
||||
this.lasttime = new Date();
|
||||
}
|
||||
BaseGame.prototype = new events.EventEmitter();
|
||||
|
||||
BaseGame.prototype.tag = function () {
|
||||
if (this.pname === undefined || this.gname === undefined)
|
||||
return "";
|
||||
return this.gname + "/" + this.pname;
|
||||
};
|
||||
|
||||
BaseGame.prototype.framepush = function(chunk) {
|
||||
/* If this chunk resets the screen, discard what preceded it. */
|
||||
if (isclear(chunk)) {
|
||||
this.replaybuf = new Buffer(1024);
|
||||
this.replaylen = 0;
|
||||
}
|
||||
/* Make sure there's space. */
|
||||
while (this.replaybuf.length < chunk.length + this.replaylen) {
|
||||
var nbuf = new Buffer(this.replaybuf.length * 2);
|
||||
this.replaybuf.copy(nbuf, 0, 0, this.replaylen);
|
||||
this.replaybuf = nbuf;
|
||||
if (this.replaybuf.length > 65536) {
|
||||
tslog("Warning: %s frame buffer at %d bytes", this.tag(),
|
||||
this.replaybuf.length);
|
||||
}
|
||||
}
|
||||
chunk.copy(this.replaybuf, this.replaylen);
|
||||
this.replaylen += chunk.length;
|
||||
};
|
||||
|
||||
/* Adds a watcher. */
|
||||
BaseGame.prototype.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.gname
|
||||
}));
|
||||
conn.sendUTF(JSON.stringify({"t": "d",
|
||||
"d": this.replaybuf.toString("hex", 0, this.replaylen)}));
|
||||
conn.on('close', this.detach.bind(this, conn));
|
||||
this.watchers.push(conn);
|
||||
};
|
||||
|
||||
BaseGame.prototype.detach = function (socket) {
|
||||
var n = this.watchers.indexOf(socket);
|
||||
if (n >= 0) {
|
||||
this.watchers.splice(n, 1);
|
||||
tslog("A WebSocket watcher has left game %s", this.tag());
|
||||
}
|
||||
};
|
||||
|
||||
/* Constructor. A TermSession handles a pty and the game running on it.
|
||||
* gname: (String) Name of the game to launch.
|
||||
|
|
@ -78,8 +137,7 @@ var gamemux = new events.EventEmitter();
|
|||
* "exit": Child terminated. Parameters: none
|
||||
*/
|
||||
function TermSession(gname, pname, wsReq) {
|
||||
/* Subclass EventEmitter to do the hard work. */
|
||||
events.EventEmitter.call(this);
|
||||
BaseGame.call(this);
|
||||
/* Don't launch anything that's not a real game. */
|
||||
if (gname in games) {
|
||||
this.game = games[gname];
|
||||
|
|
@ -113,7 +171,6 @@ function TermSession(gname, pname, wsReq) {
|
|||
sessions[this.gname + "/" + this.pname] = this;
|
||||
gamemux.emit('begin', this.gname, this.pname, 'rlg');
|
||||
/* Set up the lockfile and ttyrec */
|
||||
this.lasttime = new Date();
|
||||
var ts = timestamp(this.lasttime);
|
||||
var progressdir = path.join("/dgldir/inprogress", this.gname);
|
||||
this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec");
|
||||
|
|
@ -122,16 +179,10 @@ function TermSession(gname, pname, wsReq) {
|
|||
var ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname,
|
||||
ts + ".ttyrec");
|
||||
this.record = fs.createWriteStream(ttyrec, { mode: 0664 });
|
||||
/* Holds the output since the last screen clear, so watchers can begin
|
||||
* with a complete screen. */
|
||||
this.framebuf = new Buffer(1024);
|
||||
this.frameoff = 0;
|
||||
/* The player's WebSocket and its handlers. */
|
||||
this.playerconn = wsReq.accept(null, wsReq.origin);
|
||||
this.playerconn.on('message', this.input_msg.bind(this));
|
||||
this.playerconn.on('close', this.close.bind(this));
|
||||
/* Array for watcher connections. */
|
||||
this.watchers = [];
|
||||
/* Send initial data. */
|
||||
this.playerconn.sendUTF(JSON.stringify({"t": "s", "w": this.w, "h": this.h,
|
||||
"p": this.pname, "g": this.gname}));
|
||||
|
|
@ -147,33 +198,7 @@ function TermSession(gname, pname, wsReq) {
|
|||
this.term.on("data", this.write_ttyrec.bind(this));
|
||||
this.term.on("exit", this.destroy.bind(this));
|
||||
}
|
||||
TermSession.prototype = new events.EventEmitter();
|
||||
|
||||
TermSession.prototype.tag = function () {
|
||||
if (this.pname === undefined || this.gname === undefined)
|
||||
return "";
|
||||
return this.gname + "/" + this.pname;
|
||||
};
|
||||
|
||||
TermSession.prototype.framepush = function(chunk) {
|
||||
/* If this chunk resets the screen, discard what preceded it. */
|
||||
if (isclear(chunk)) {
|
||||
this.framebuf = new Buffer(1024);
|
||||
this.frameoff = 0;
|
||||
}
|
||||
/* Make sure there's space. */
|
||||
while (this.framebuf.length < chunk.length + this.frameoff) {
|
||||
var nbuf = new Buffer(this.framebuf.length * 2);
|
||||
this.framebuf.copy(nbuf, 0, 0, this.frameoff);
|
||||
this.framebuf = nbuf;
|
||||
if (this.framebuf.length > 65536) {
|
||||
tslog("Warning: Game %s frame buffer at %d bytes", this.tag(),
|
||||
this.framebuf.length);
|
||||
}
|
||||
}
|
||||
chunk.copy(this.framebuf, this.frameoff);
|
||||
this.frameoff += chunk.length;
|
||||
};
|
||||
TermSession.prototype = new BaseGame();
|
||||
|
||||
/* Currently this also sends to the player and any watchers. */
|
||||
TermSession.prototype.write_ttyrec = function (datastr) {
|
||||
|
|
@ -244,29 +269,9 @@ TermSession.prototype.destroy = function () {
|
|||
tslog("Game %s ended.", tag);
|
||||
};
|
||||
|
||||
/* Adds a watcher. */
|
||||
TermSession.prototype.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.gname
|
||||
}));
|
||||
conn.sendUTF(JSON.stringify({"t": "d",
|
||||
"d": this.framebuf.toString("hex", 0, this.frameoff)}));
|
||||
conn.on('close', this.detach.bind(this, conn));
|
||||
this.watchers.push(conn);
|
||||
};
|
||||
|
||||
TermSession.prototype.detach = function (socket) {
|
||||
var n = this.watchers.indexOf(socket);
|
||||
if (n >= 0) {
|
||||
this.watchers.splice(n, 1);
|
||||
tslog("A WebSocket watcher has left game %s", this.tag());
|
||||
}
|
||||
};
|
||||
|
||||
function DglSession(filename) {
|
||||
var ss = this;
|
||||
events.EventEmitter.call(this);
|
||||
BaseGame.call(this);
|
||||
var pathcoms = filename.split('/');
|
||||
this.gname = pathcoms[pathcoms.length - 2];
|
||||
if (!(this.gname in games)) {
|
||||
|
|
@ -282,27 +287,6 @@ function DglSession(filename) {
|
|||
* getting into a race. */
|
||||
this.reading = false;
|
||||
this.rpos = 0;
|
||||
this.framebuf = new Buffer(1024);
|
||||
this.frameoff = 0;
|
||||
this.framepush = function(chunk) {
|
||||
/* If this chunk resets the screen, discard what preceded it. */
|
||||
if (isclear(chunk)) {
|
||||
this.framebuf = new Buffer(1024);
|
||||
this.frameoff = 0;
|
||||
}
|
||||
/* Make sure there's space. */
|
||||
while (this.framebuf.length < chunk.length + this.frameoff) {
|
||||
var nbuf = new Buffer(this.framebuf.length * 2);
|
||||
this.framebuf.copy(nbuf, 0, 0, this.frameoff);
|
||||
this.framebuf = nbuf;
|
||||
if (this.framebuf.length > 65536) {
|
||||
tslog("Warning: DGL %s frame buffer at %d bytes", this.tag(),
|
||||
this.framebuf.length);
|
||||
}
|
||||
}
|
||||
chunk.copy(this.framebuf, this.frameoff);
|
||||
this.frameoff += chunk.length;
|
||||
};
|
||||
this.readchunk = function () {
|
||||
if (this.reading)
|
||||
return;
|
||||
|
|
@ -375,9 +359,6 @@ function DglSession(filename) {
|
|||
}
|
||||
});
|
||||
});
|
||||
this.tag = function () {
|
||||
return this.gname + "/" + this.pname;
|
||||
};
|
||||
this.close = function () {
|
||||
this.recwatcher.close()
|
||||
/* Ensure all data is handled before quitting. */
|
||||
|
|
@ -393,29 +374,8 @@ function DglSession(filename) {
|
|||
gamemux.emit('end', this.gname, this.pname);
|
||||
tslog("DGL %s: closed", ss.tag());
|
||||
};
|
||||
this.watchers = [];
|
||||
/* 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.gname
|
||||
}));
|
||||
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 DGL game %s", ss.tag());
|
||||
}
|
||||
});
|
||||
this.watchers.push(conn);
|
||||
};
|
||||
this.lasttime = new Date();
|
||||
}
|
||||
DglSession.prototype = new events.EventEmitter();
|
||||
DglSession.prototype = new BaseGame();
|
||||
|
||||
function wsStartGame(wsReq) {
|
||||
var playmatch = wsReq.resourceURL.pathname.match(/^\/play\/([^\/]*)$/);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue