Juggernaut: Invirtiendo el paradigma Cliente/Servidor

Juggernaut, además de ser un personaje del universo Marvel, es un servidor escrito en Node.JS, que permite su integración con Ruby on Rails para realizar el intercambio de mensajes en dirección del servidor hacia el navegador.

Este esquema permite al servidor poder enviar mensajes al navegador en cualquier momento, de modo que se mantiene una actualización mucho más precisa que con refrescos esporádicos del navegador web hacia el servidor.

¿Cómo funciona?

Juggernaut, para conseguir esto se basa en el uso de un código en Flash que le permite abrir un socket y mantener la comunicación con el servidor de forma constante. En la parte del cliente, por lo tanto, está el navegador que realiza las peticiones al código de Rails como siempre y, además, el código Flash que abre la comunicación con el servidor de Juggernaut, que le va enviando código en JavaScript que ejecuta para realizar acciones concretas.

En la parte del servidor tenemos también dos elementos bien diferenciados, por un lado tenemos al servidor de Juggernaut ejecutándose en el puerto 5001 (por defecto) y el servidor de Rails ejecutándose en otro puerto (por defecto en desarrollo suele ser el 3000). La comunicación con el servidor de Rails es como siempre en protocolo HTTP, mientras que el intercambio de información a través del interfaz de Juggernaut se sucede en formato JSON, enviando información específica a ejecutar en el navegador.

Instalación

La verdad es que la instalación no queda nada clara, por lo que voy a explicar el cómo se instala el sistema para tenerlo funcionando en poco tiempo. En principio, necesitamos ejecutar lo siguiente:

gem install json
gem install eventmachine
gem install juggernaut
gem install maccman-juggernaut -s http://gems.github.com

Tenemos que crear un proyecto Rails. En principio, tendrá que ser una versión anterior a la 3.2, ya que en esa versión se ha eliminado el uso de plugins en favor de las gemas, por lo que, creamos nuestro proyecto Rails y ejecutamos:

ruby script/plugin install git://github.com/maccman/juggernaut_plugin.git

Ahora toca lanzar la parte servidora de Juggernaut, para eso, vamos a generar un fichero de configuración, el sistema nos puede generar uno automáticamente de la siguiente forma:

juggernaut -g juggernaut.yml

Con esto ya tenemos instalado todo el sistema de Juggernaut, y lo básico para poder integrarlo dentro de nuestro proyecto Rails.

Implementando Juggernaut en Rails

Introducir Juggernaut en Rails es tan sencillo como crear un nuevo controlador, por ejemplo uno llamado Chat, y escribir el siguiente código en el fichero chat_controller.rb:

class ChatController < ApplicationController
  def index
  end
 
  def send_data
    render :juggernaut do |page|
        page.insert_html :top, 'chat_data', "<li><strong>#{params['id']}</strong>: #{h params['chat_input']}</li>"
    end
    render :nothing => true
  end
 
end

En este código tenemos dos entradas, una es el index que lo emplearemos para entrar en la página inicial, y otra es la parte de envío de datos, a la que llamaremos mediante AJAX. El formulario lo montamos de la siguiente forma en el fichero index.html.erb:

<html>
<head>
    <title>Chat</title>
    <%= javascript_include_tag :defaults, :juggernaut %>
    <%= juggernaut(:client_id => params[:id]) %>
</head>
<body>
    <%= form_remote_tag(
          :url => { :action => :send_data },
          :complete => "$('chat_input').value = ''" ) %>
    <%= text_field_tag( 'chat_input', '', { :size => 20, :id => 'chat_input'} ) %>
    <%= hidden_field_tag( 'id', params[:id] ) %>
    <%= submit_tag "Add" %>
    </form>
    <ul id="chat_data" style="list-style:none">
    </ul>
</body>
</html>

Lanzando la aplicación

Lanzamos Rails (ya sea con mongrel, thin o cualquier otro servidor) y Juggernaut. El lanzamiento de Juggernaut lo podemos hacer de la siguiente forma:

juggernaut -c juggernaut.yml

Ahora vamos al navegador, abrimos dos navegadores:

Si vamos escribiendo en una ventana, veremos como van apareciendo los textos en ambas, algo como esto:

Con lo que comprobamos que el sistema funciona correctamente.

Algunas pegas

Como hemos visto desde el principio, la comunicación del navegador se realiza a través de un puerto que no es el 80, típico del protocolo HTTP, y que tampoco es protocolo HTTP lo que transita por ese puerto, por lo que, en instalaciones con acceso a Internet restringido, es posible que este sistema no funcione correctamente.

Además, se suma el problema de que el puerto 5001 debe de mantenerse abierto hacia Internet, si no configuramos con suficiente seguridad, a través del fichero juggernaut.yml el sistema, podemos encontrarnos un verdadero agujero de seguridad… ya depende de para qué usemos Juggernaut, pero teniendo en cuenta de que ejecuta código JavaScript en el cliente, podría ser algo nocivo.

Conclusiones

Esta aproximación al sistema de Juggernaut ha sido bastante interesante para descubrir una forma de realizar este tipo de comunicaciones entre cliente y servidor de forma inversa, es decir, que el servidor pueda enviar información al cliente sin que el cliente la solicite. No obstante, los navegadores actuales implementan un sistema denominado websocket que tenderá a sustituir estos mecanismos artesanos de una forma más estándar y frameworks como ChicagoBoss ya lo implementan de forma nativa. El futuro nos mostrará los caminos que se van tomando, de momento, Juggernaut es una muy buena solución para todos los navegadores web actuales.