Mercurial > hg > rlgwebd
diff webtty.js @ 140:789c094675f4
WebTTY: use WebSockets when possible.
author | John "Elwin" Edwards |
---|---|
date | Mon, 22 Jul 2013 07:51:53 -0700 |
parents | f14e92f6d955 |
children | c4a32007d2dc |
line wrap: on
line diff
--- a/webtty.js Sat Jul 20 12:23:53 2013 -0700 +++ b/webtty.js Mon Jul 22 07:51:53 2013 -0700 @@ -6,15 +6,83 @@ 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 @@ 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');