boldr by Nicolas Mérouze

Twitter/HTML5 Websockets with Cramp

After HTML5 Web Storage, I'm gonna show a use case of HTML5 Websockets. It's quickly becoming a hype solution for bidirectional communication between client and server (think TCP for browsers). Hype but not really usable in production because of the compatibility with the browsers.

Compatibility of Websockets (as of January 2010) : nightly builds of WebKit and Chrome.

Because I'm lazy and there are some examples out there I decided to convert an existing Twitter Stream example to Cramp (a new Ruby async framework by @lifo from the Rails Core team). So first read the article from the author of the initial example. Finish? Now we can convert it to Cramp.

Cramp for Websockets

Lifo introduced it on his blog. A few lines later we have the application configured for Cramp instead of EventMachine in socket.rb:

require 'vendor/gems/environment'
require 'cramp/controller'
require 'uuid'
require 'mq'

Cramp::Controller::Websocket.backend = :thin

class TweetsController < Cramp::Controller::Websocket
end

Rack::Handler::Thin.run TweetsController, :Port => 3000

on_start

Now we want to convert the open event to Cramp. For that, Cramp has a on_start method to call the method executed for this event. So the open event will be like that:

require 'vendor/gems/environment'
require 'cramp/controller'
require 'uuid'
require 'mq'

Cramp::Controller::Websocket.backend = :thin

class TweetsController < Cramp::Controller::Websocket
  @@uuid = UUID.new

  on_start :display

  def display
    puts "WebSocket opened"

    twitter = MQ.new
    twitter.queue(@@uuid.generate).bind(twitter.fanout('twitter')).subscribe do |t|
      render t
    end
  end
end

Rack::Handler::Thin.run TweetsController, :Port => 3000

To send a message to the user, Cramp has a render method.

on_finish

When the user ends the execution of the socket, there's a close event. When this event is fired, the method passed to on_finish will be executed.

require 'vendor/gems/environment'
require 'cramp/controller'
require 'uuid'
require 'mq'

Cramp::Controller::Websocket.backend = :thin

class TweetsController < Cramp::Controller::Websocket
  @@uuid = UUID.new

  on_start :display
  on_finish :close

  def display
    puts "WebSocket opened"

    twitter = MQ.new
    twitter.queue(@@uuid.generate).bind(twitter.fanout('twitter')).subscribe do |t|
      render t
    end
  end

  def close
    puts "WebSocket closed"
  end
end

Rack::Handler::Thin.run TweetsController, :Port => 3000

We just have to start the server and test with client.html to see the tweets.

Conclusion

If you read the code you'll see that Websockets make more sense to a developer than Comet. And it's the same for a lot of HTML5 features. Having more logical things and less hacks will may finally be a reality soon. You can see the whole code of this example in my fork of the original one.

If you liked the article and/or want to talk to me about it, you can follow me on twitter.