UNPKG

bonescriptjtjk

Version:

Physical computing library for embedded Linux

188 lines (166 loc) 6 kB
// Copyright (C) 2011 - Texas Instruments, Jason Kridner // // var b = require('../main'); var fs = require('fs'); var url = require('url'); var child_process = require('child_process'); var winston = require('winston'); var socketio = require('socket.io'); var debug = process.env.DEBUG ? true : false; exports.socketJSReqHandler = function(req, res) { function sendFile(err, file) { if(err) { res.writeHead(500, {"Content-Type": "text/plain"}); res.end(err + '\n'); return; } res.setHeader('Content-Type', 'text/javascript'); file = file.replace(/___INSERT_HOST___/g, host); res.end(file); } var parsedUrl = url.parse(req.url); var uri = parsedUrl.pathname; var host = 'http://' + req.headers.host; if(uri == '/bonescript.js') { var filename = __dirname + '/bonescript.js'; if(debug) winston.debug('filename = ' + filename) fs.readFile(filename, 'utf8', sendFile); } } exports.addSocketListeners = function(server, serverEmitter) { var io = socketio(server); if(debug) winston.debug('Listening for new socket.io clients'); io.on('connection', onconnect); function onconnect(socket) { winston.debug('Client connected'); serverEmitter.emit('socket$connect', socket); // on disconnect socket.on('disconnect', function() { if(debug) winston.debug('Client disconnected'); serverEmitter.emit('socket$disconnect'); }); socket.on('message', serverMessage); spawn(socket); var modmsg = {}; modmsg.module = 'bonescript'; modmsg.data = {}; var callMyFunc = function(name, m) { var myCallback = function(resp) { if(debug) winston.debug(name + ' replied to ' + JSON.stringify(m) + ' with ' + JSON.stringify(resp)); if(typeof m.seq == 'undefined') return; if(!resp || (typeof resp != 'object')) resp = {'data': resp}; resp.seq = m.seq; // TODO: consider setting 'oneshot' if(debug) winston.debug('Sending message "bonescript": ' + JSON.stringify(resp)); socket.emit('bonescript', resp); }; try { var callargs = []; for(var arg in b[name].args) { var argname = b[name].args[arg]; if(argname == 'callback') { if(typeof m.seq == 'number') callargs.push(myCallback); else callargs.push(null); } else if(typeof m[argname] != 'undefined') { callargs.push(m[argname]); } else { callargs.push(undefined); } } if(debug) winston.debug('Calling ' + name + '(' + callargs.join(',') + ')'); b[name].apply(this, callargs); } catch(ex) { if(debug) winston.debug('Error handing ' + name + ' message: ' + ex); if(debug) winston.debug('m = ' + JSON.stringify(m)); } }; var addSocketX = function(message, name) { var onFuncMessage = function(m) { callMyFunc(name, m); }; socket.on(message, onFuncMessage); }; var b = require('../main'); for(var i in b) { if(typeof b[i] == 'function') { if(typeof b[i].args != 'undefined') { modmsg.data[i] = {}; modmsg.data[i].name = i; modmsg.data[i].type = 'function'; modmsg.data[i].value = b[i].args; addSocketX('bonescript$' + i, i); } } else { modmsg.data[i] = {}; modmsg.data[i].name = i; modmsg.data[i].type = typeof b[i]; modmsg.data[i].value = b[i]; } } socket.emit('require', modmsg); } function serverMessage(message) { serverEmitter.emit('message', message); } return(io); } // most heavily borrowed from https://github.com/itchyny/browsershell function spawn(socket) { var stream = ''; var timer; var len = 0; var c; socket.on('shell', receive); return(receive); function receive(msg) { if(!c) { try { if(debug) winston.debug('Spawning bash'); c = child_process.spawn('/bin/bash', ['-i'], {customFds: [-1, -1, -1]}); c.stdout.on('data', send); c.stderr.on('data', send); c.on('exit', function() { socket.emit('shell', send('\nexited\n')); c = undefined; }); socket.on('disconnect', function () { if(debug) winston.debug('Killing bash'); c.kill('SIGHUP'); }); } catch(ex) { c = undefined; send('Error invoking bash'); winston.error('Error invoking bash'); } } if(c) { if(msg) { c.stdin.write(msg + '\n', 'utf-8'); } } else { winston.error('Unable to invoke child process'); } } function send(data) { // add data to the stream stream += data.toString(); ++len; // clear any existing timeout if it exists if(timer) clearTimeout(timer); // set new timeout timer = setTimeout(function () { socket.emit('shell', stream); stream = ''; len = 0; }, 100); // send data if over threshold if(len > 1000) { clearTimeout(timer); socket.emit('shell', stream); stream = ''; len = 0; } } }