Quantcast
Viewing all articles
Browse latest Browse all 10

Redirecting stdout of a process to a web page using websockets (socket.io)

I’m working on new features for init, meanwhile I’m also improving the development process so I’m working hard to add automated task with grunt. But since I added AMD and a few test with mocha.js and phantom.js my grunt-watch is getting slower and slower, but the real problem is that I’m using both of my monitors for development,

One with sublime

Image may be NSFW.
Clik here to view.
Captura de pantalla 2013-07-30 a la(s) 23.33.10

and the other with chrome and the inspector

Image may be NSFW.
Clik here to view.
Captura de pantalla 2013-07-30 a la(s) 23.33.10 (2)

So I don’t have space to see if my grunt automated build task has been successful. Usually I save (cmd+s) and then refresh the browser to find out that nothing works, just then I go to my terminal (cmd+tab) to see what happened and then realize that the build task for “X” task failed.
So I needed a third monitor just to see what was happening with my “grunt-watch” output. I know I could connect it to growl or use the live reloading feature, but I decided to do a much more fun exercise.

Spawning a process in node.js

To start I need to spawn a new process (grunt-watch) from node and listen the stdout. This is very easy thanks to the “child-process” module bundled with node.

var spawn = require(“child_process”).spawn;
watch = spawn(“grunt”, ["watch"]);

watch.stdout.on(“data”, function(data){
console.log(data);
});

Now to the tricky thing, how to redirect this to a web socket? well that’s easy, because using socket.io is easy. Just create your connect app (that’s easier),
and then listen to any data coming from the spawned process and emit that data through the socket.

var connect = require(“connect”),
app = connect().use(connect.static(“watch”)).listen(3000);
io = require(“socket.io”).listen(app);
buffer = “”;

io.configure(“development”, function(){
io.set(“log level”, 0);
});

io.sockets.on(“connection”, function(socket){
var watch;

socket.on(“init”, function(data){
watch = spawn(“grunt”, ["watch"]);
watch.stdout.on(“data”, function(data){
console.log(data.toString());
socket.emit(“data”, data.toString());
});
});

socket.on(“disconnect”, function(){
console.log(“finishing watch”);
watch.kill(‘SIGHUP’);
});
});

Now, for the client side it’s even much more easy. You just need to connect to the websocket and emit the “init” event to start the spawn process on the server, and just listen for any “data” coming. Then I’m just prepending a “pre” element with the string coming from the stdout, as you can see we are calling “.toString()” in the server because it is a byte stream and must be converted to a UTF8 string before sending it to the client

(function(){
var socket = io.connect(),
body = document.body;

socket.emit(“init”);
socket.on(“data”, function(data){
var pre = document.createElement(“pre”),
i;
pre.innerHTML = data;
if(body.childNodes.length >0){
body.insertBefore(pre, body.firstChild);
}else{
body.appendChild(pre);
}
if(body.childNodes.length > 100){
for (i = 0; i< 50; i += 1){
body.removeChild(body.childNodes[body.childNodes.length]);
}
}
});
}());

I’m also deleting old “pre” element if i have more than 100 to avoid overloading the browser.

and that’s all, now I can use my iphone (or any device with a browser) to see what happened with my grunt automated tasks

just checkout the code from

https://github.com/picanteverde/watch

and you are ready to go

Estoy trabajando en nuevas características para init, mientras tanto tambien estoy mejorando el proceso de desarrollo por lo que estoy trabajando duro para añadir tareas automatizadas con grunt. Pero como he añadido AMD y unos pocos test con mocha.js y phantom.js y ademas grunt-watch que es cada vez más lento, pero el verdadero problema es que estoy usando mis dos monitores para el desarrollo,
Uno con sublime

Image may be NSFW.
Clik here to view.
Captura de pantalla 2013-07-30 a la(s) 23.33.10

y el otro con chrome y el inspector,

Image may be NSFW.
Clik here to view.
Captura de pantalla 2013-07-30 a la(s) 23.33.10 (2)

Así que no tengo espacio para ver si mis tareas automatizadas con grunt han sido exitosas o no. Por lo general,  guardo (cmd + s) y actualizo el navegador y me encuentro que nada funciona, en ese momento me voy al terminal (cmd + tab) para ver lo que pasó y luego darme cuenta de que la tarea de compilación para la tarea “X” ha fallado.
Así que necesitaba un tercer monitor sólo para ver lo que estaba pasando con mi salida “grunt-watch”. Sé que podría conectarlo a growl o utilizar la función de Live Reloading, pero me decidí a hacer algo mucho más divertido.

Lanzando un proceso en Node.js

Para empezar tengo que generar un nuevo proceso (grunt-watch) desde node.js y escuchar la stdout. Esto es muy fácil gracias al módulo “child-process” incluido en node.

var spawn = require(“child_process”).spawn;
watch = spawn(“grunt”, ["watch"]);

watch.stdout.on(“data”, function(data){
console.log(data);
});

Ahora a lo difícil, cómo redirigir el stdout a un websocket ? bueno, eso es fácil, porque el uso de socket.io es fácil. Basta con crear su aplicación de connect (que es muy fácil),
y luego escuchar a los datos procedentes del proceso generado y emitir esos datos a través del socket.

var connect = require(“connect”),
app = connect().use(connect.static(“watch”)).listen(3000);
io = require(“socket.io”).listen(app);
buffer = “”;

io.configure(“development”, function(){
io.set(“log level”, 0);
});

io.sockets.on(“connection”, function(socket){
var watch;

socket.on(“init”, function(data){
watch = spawn(“grunt”, ["watch"]);
watch.stdout.on(“data”, function(data){
console.log(data.toString());
socket.emit(“data”, data.toString());
});
});

socket.on(“disconnect”, function(){
console.log(“finishing watch”);
watch.kill(‘SIGHUP’);
});
});

Ahora, para el cliente es aún mucho más fácil. Sólo tienes que conectar el websocket y emitir el evento “init” para iniciar el proceso en el servidor, y sólo escuchar el evento “data” que llegue. Entonces pre- agregar elementos “pre” con la cadena que viene del stdout, como se puede ver estamos llamando “. toString ()” en el servidor, ya que se trata de un stream de bytes y se debe convertir en una cadena UTF8 antes enviarlo al cliente

(function(){
var socket = io.connect(),
body = document.body;

socket.emit(“init”);
socket.on(“data”, function(data){
var pre = document.createElement(“pre”),
i;
pre.innerHTML = data;
if(body.childNodes.length >0){
body.insertBefore(pre, body.firstChild);
}else{
body.appendChild(pre);
}
if(body.childNodes.length > 100){
for (i = 0; i< 50; i += 1){
body.removeChild(body.childNodes[body.childNodes.length]);
}
}
});
}());

También estoy borrando todos los viejos “pre” si tengo más de 100, para evitar sobrecargar el navegador

Y eso es todo ahora puedo usar mi iphone (o cualquier otro dispositivo con un browser) como tercera pantalla para ver el resultado de mis tareas en grunt.

simplemente copia el código de

https://github.com/picanteverde/watch

y estarás listo para usarlo


Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

Viewing all articles
Browse latest Browse all 10

Trending Articles