Realtime updates with WebSocket

Agenda

Alternativas

WebSocket

Características

Protocolo

Handshake

El cliente envía un request al servidor indicando que quiere cambiar protocolos de HTTP a WebSocket mediante el header Upgrade.

GET ws://echo.websocket.org/?encoding=text HTTP/1.1
Origin: http://websocket.org
Cookie: __utma=99as
Connection: Upgrade
Host: echo.websocket.org
Sec-WebSocket-Key: uRovscZjNol/umbTt5uKmw==
Upgrade: websocket
Sec-WebSocket-Version: 13

Si el servidor entiende el protocolo WebSocket, acepta cambiar el protocolo mediante el header Upgrade.

HTTP/1.1 101 WebSocket Protocol Handshake
Date: Fri, 10 Feb 2012 17:38:18 GMT
Connection: Upgrade
Server: Kaazing Gateway
Upgrade: WebSocket
Access-Control-Allow-Origin: http://websocket.org
Access-Control-Allow-Credentials: true
Sec-WebSocket-Accept: rLHCkw/SKsO9GAH/ZSFhBATDKrU=
Access-Control-Allow-Headers: content-type

En este momento la conexión HTTP es reemplazada por la conexión WebSocket en la misma conexión TCP/IP subyacente.

Caso de éxito

Motivación

Soluciones

Realtime updates con WebSocket

Un caso puntual: actualizar una página cuando un dispositivo se conecta

Ejemplo

Aplicación que envía un mensaje al servidor WebSocket y recibe una respuesta, la cual imprime en la pantalla.

Antes de empezar

source 'https://rubygems.org'

gem 'em-websocket'
gem 'rack'

Servidor WebSocket

require 'bundler/setup'
require 'em-websocket'

EM.run do
  EM::WebSocket.start host: '0.0.0.0', port: '8080' do |ws|
    ws.onmessage do |message|
      ws.send "[#{Time.now.strftime '%D %T'}] #{message}"
    end
  end
end

Web app

require 'bundler/setup'
require 'rack'

app = ->(env) do
  tpl = File.read File.join(__dir__, 'views', 'index.html')
  Rack::Response.new [tpl], 200, {}
end

run app

Template: WebSocket Javascript API

<!DOCTYPE html>
<html>
  <head>
    <title>WebSocket demo</title>
  </head>
  <body>
    <h1>WebSocket demo</h1>
    <form action="javascript:;" id="send-message">
      <input type="text" id="message">
      <input type="submit">
    </form>
    <ul id="messages"></ul>
    <script>
      function appendMessage(message) {
        var element = document.createElement('li');
        element.innerText = message;

        var messages = document.querySelector('#messages');
        messages.appendChild(element);
      }

      document.addEventListener('DOMContentLoaded', function() {
        ws = new WebSocket('ws://localhost:8080');

        ws.onerror = function(event) {
          appendMessage(':(');
        }

        ws.onmessage = function(event) {
          appendMessage(event.data);
        };

        var form = document.querySelector('#send-message');
        form.onsubmit = function(event) {
          event.preventDefault();

          var message = document.querySelector('#message');
          ws.send(message.value);
        }
      });
    </script>
  </body>
</html>

¿Preguntas?

¡Gracias!