unhosted web apps

freedom from web 2.0's monopoly platforms

4. WebSockets

(en Français)

No Cookie Crew - Warning #2: For this tutorial you will need to update your personal server using an ssh/scp client.

WebSockets are a great way to get fast two-way communication working between your unhosted web app and your personal server. It seems the best server-side WebSocket support, at least under nodejs, comes from SockJS (but see also engine.io). Try installing this nodejs script:


var sockjs = require('sockjs'),
    fs = require('fs'),
    https = require('https'),
    config = require('./config.js').config;

function handle(conn, chunk) {
  conn.write(chunk);
}

var httpsServer = https.createServer({ 
  key: fs.readFileSync(config.tlsDir+'/tls.key'), 
  cert: fs.readFileSync(config.tlsDir+'/tls.cert'), 
  ca: fs.readFileSync(config.tlsDir+'/ca.pem') 
}, function(req, res) {
  res.writeHead(200); 
  res.end('connect a WebSocket please'); 
});
httpsServer.listen(config.port);

var sockServer = sockjs.createServer();
sockServer.on('connection', function(conn) {
  conn.on('data', function(chunk) {
    handle(conn, chunk);
  });
});
sockServer.installHandlers(httpsServer, {
  prefix:'/sock'
});
console.log('Running on port '+config.port);

and accompany it by a 'config.js' file in the same directory, like this:


exports.config = {
  tlsDir: '/path/to/tls',
  port: 1234
};

Start this script with either 'node script.js' or 'forever start script.js', and open this unhosted web app in your browser:


<!DOCTYPE html lang="en">
<html>
  <head>
    <meta charset="utf-8">
    <title>pinger</title>
  </head>
  <body>
    <p>
      Ping stats for wss://
      <input id="SockJSHost" value="example.com:1234" >
      /sock/websocket
      <input type="submit" value="reconnect"
        onclick="sock.close();" >
    </p>
    <canvas id="myCanvas" width="1000" height="1000"></canvas>
  </body>
  <script>
    var sock,
        graph = document.getElementById('myCanvas')
          .getContext('2d');
      
    function draw(time, rtt, colour) {
      var x = (time % 1000000) / 1000;//one pixel per second
      graph.beginPath();
      graph.moveTo(x, 0);
      graph.lineTo(x, rtt/10);//1000px height = 10s
      graph.strokeStyle = colour;
      graph.stroke();
      graph.fillStyle = '#eee';
      graph.rect(x, 0, 100, 1000);
      graph.fill();
    }
    
    function connect() {
      sock = new WebSocket('wss://'
        +document.getElementById('SockJSHost').value
        +'/sock/websocket');
 
      sock.onopen = function() {
        draw(new Date().getTime(), 10000, 'green');
      }
    
      sock.onmessage = function(e) {
        var sentTime = parseInt(e.data);
        var now = new Date().getTime();
        var roundTripTime = now - sentTime;
        draw(sentTime, roundTripTime, 'black');
      }
 
      sock.onclose = function() {
        draw(new Date().getTime(), 10000, 'red');
      }
    }
    connect();
    
    setInterval(function() {
      var now = new Date().getTime();
      if(sock.readyState==WebSocket.CONNECTING) {
        draw(now, 10, 'green');
      } else if(sock.readyState==WebSocket.OPEN) {
        sock.send(now);
        draw(now, 10, 'blue');
      } else if(sock.readyState==WebSocket.CLOSING) {
        draw(now, 10, 'orange');
      } else {//CLOSED or non-existent
        draw(now, 10, 'red');
        connect();
      }
    }, 1000);
  </script>
</html>

Here is a data URL for it. Open it, replace 'example.com:1234' with your own server name and leave it running for a while. It will ping your server once a second on the indicated port, and graph the round-trip time. It should look something like this:

I have quite unreliable wifi at the place I'm staying now, and even so you see that most packets eventually arrive, although some take more than 10 seconds to do so. Some notes about this:

As another example, here's what disconnecting the wifi for 15 minutes looks like:

And this is what "flatlining" looks like - the point where it goes purple is where I clicked "Reconnect".

All in all, WebSockets are a good, reliable way to connect your unhosted web app to your personal server. Next week, as promised, we will use a WebSocket for a Facebook and Twitter gateway running in nodejs. So stay tuned!

Comments welcome!

Next: Facebook and Twitter from nodejs