WebTTY: use WebSockets when possible.
This commit is contained in:
parent
fabaea6849
commit
d7df88f3cf
2 changed files with 183 additions and 18 deletions
105
webtty.js
105
webtty.js
|
|
@ -6,15 +6,83 @@ var url = require('url');
|
|||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var pty = require(path.join(localModules, "pty.js"));
|
||||
var child_process = require("child_process");
|
||||
var webSocketServer = require(path.join(localModules, "websocket")).server;
|
||||
|
||||
var serveStaticRoot = fs.realpathSync(".");
|
||||
var sessions = {};
|
||||
var sessionsWS = {};
|
||||
|
||||
var env_dontuse = {"TMUX": true, "TMUX_PANE": true};
|
||||
|
||||
/* Constructor for TermSessions. Note that it opens the terminal and
|
||||
* adds itself to the sessions dict.
|
||||
*/
|
||||
function TermSessionWS(conn, h, w) {
|
||||
var ss = this;
|
||||
/* Set up the sizes. */
|
||||
w = Math.floor(Number(w));
|
||||
if (!(w > 0 && w < 256))
|
||||
w = 80;
|
||||
this.w = w;
|
||||
h = Math.floor(Number(h));
|
||||
if (!(h > 0 && h < 256))
|
||||
h = 25;
|
||||
this.h = h;
|
||||
this.conn = conn;
|
||||
/* Customize the environment. */
|
||||
var childenv = {};
|
||||
for (var key in process.env) {
|
||||
if (!(key in env_dontuse))
|
||||
childenv[key] = process.env[key];
|
||||
}
|
||||
var spawnopts = {"env": childenv, "cwd": process.env["HOME"],
|
||||
"rows": this.h, "cols": this.w};
|
||||
this.term = pty.spawn("bash", [], spawnopts);
|
||||
this.alive = true;
|
||||
this.term.on("data", function (datastr) {
|
||||
var buf = new Buffer(datastr);
|
||||
if (ss.conn.connected)
|
||||
ss.conn.sendUTF(JSON.stringify({"t": "d", "d": buf.toString("hex")}));
|
||||
});
|
||||
this.term.on("exit", function () {
|
||||
ss.alive = false;
|
||||
/* Wait for all the data to get collected */
|
||||
setTimeout(ss.cleanup, 1000);
|
||||
});
|
||||
this.conn.on("message", function (msg) {
|
||||
try {
|
||||
var msgObj = JSON.parse(msg.utf8Data);
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
if (msgObj.t == "d") {
|
||||
var hexstr = msgObj["d"].replace(/[^0-9a-f]/gi, "");
|
||||
if (hexstr.length % 2 != 0) {
|
||||
return;
|
||||
}
|
||||
var keybuf = new Buffer(hexstr, "hex");
|
||||
ss.term.write(keybuf);
|
||||
}
|
||||
});
|
||||
this.conn.on("close", function (msg) {
|
||||
if (ss.alive)
|
||||
ss.term.kill('SIGHUP');
|
||||
console.log("WebSocket connection closed.");
|
||||
});
|
||||
this.cleanup = function () {
|
||||
/* Call this when the child is dead. */
|
||||
if (ss.alive)
|
||||
return;
|
||||
if (ss.conn.connected) {
|
||||
ss.conn.sendUTF(JSON.stringify({"t": "q"}));
|
||||
}
|
||||
};
|
||||
this.conn.sendUTF(JSON.stringify({"t": "l", "w": w, "h": h}));
|
||||
console.log("New WebSocket connection.");
|
||||
}
|
||||
|
||||
function TermSession(sessid, h, w) {
|
||||
/* Set up the sizes. */
|
||||
w = Math.floor(Number(w));
|
||||
|
|
@ -355,6 +423,41 @@ process.on("exit", function () {
|
|||
return;
|
||||
});
|
||||
|
||||
function wsRespond(req) {
|
||||
var w, h, conn;
|
||||
if (req.resourceURL.pathname == "/sock") {
|
||||
w = parseInt(req.resourceURL.query.w);
|
||||
if (isNaN(w) || w <= 0 || w > 256)
|
||||
w = 80;
|
||||
h = parseInt(req.resourceURL.query.h);
|
||||
if (isNaN(h) || h <= 0 || h > 256)
|
||||
h = 25;
|
||||
conn = req.accept(null, req.origin);
|
||||
new TermSessionWS(conn, h, w);
|
||||
}
|
||||
else {
|
||||
req.reject(404, "No such resource.");
|
||||
}
|
||||
}
|
||||
|
||||
/* The pty.js module doesn't wait for the processes it spawns, so they
|
||||
* become zombies, which leads to unpleasantness when the system runs
|
||||
* out of process table entries. But if the child_process module is
|
||||
* initialized and a child spawned, node will continue waiting for any
|
||||
* children.
|
||||
* Someday, some developer will get the bright idea of tracking how many
|
||||
* processes the child_process module has spawned, and not waiting if
|
||||
* it's zero. Until then, the following useless line will protect us
|
||||
* from the zombie hordes.
|
||||
* Figuring this out was almost as interesting as the Rogue bug where
|
||||
* printf debugging altered whether the high score list was checked.
|
||||
*/
|
||||
child_process.spawn("/bin/true");
|
||||
|
||||
process.env["TERM"] = "xterm-256color";
|
||||
http.createServer(handler).listen(8080, "127.0.0.1");
|
||||
var webServer = http.createServer(handler);
|
||||
webServer.listen(8080, "127.0.0.1");
|
||||
console.log('Server running at http://127.0.0.1:8080/');
|
||||
var wsServer = new webSocketServer({"httpServer": webServer});
|
||||
wsServer.on("request", wsRespond);
|
||||
console.log('WebSockets online');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue