em-eventsource - an EventMachine client for Server-Sent Events

About Server-Sent events

With all the buzz around HTML5 and related technologies, some specifications get much more attention than some others. A quite subdued one is the Server-Sent Events spec.

It is also known as EventSource. It allows you to consume a streaming API (aka. streaming server) with a very simple javascript API. On the client side, you’d write something like this:

var source = new EventSource("http://example.com/streaming")
source.onmessage = function(message) {
    console.log("got new message:", message.data)
}

The streaming API is made available by example.com/streaming by enforcing a few conventions for the response payloads. The protocol is pretty straightforward:

HTTP1/1 200 OK
Content-Type: text/event-stream

data: my message
data: a new one

It is all about the Content-Type, and streamed (chunked) body. With the previous response, you will have this result in your js debug console:

got new message: my message
got new message: a new one

You can even have a multiline message, with a name.

data: Chuck has joined
data: the meeting room
event: join

You can thus listen for join events:

source.addEventListener("join", function(message) {
    console.log("join", message.data)
})

At this point, you should have notice Server-Sent Events is quite different from WebSockets: you don’t have any bidirectonial stream. This is currently the only good way to consume a streaming API in Javascript, with a simple protocol.

Our EventMachine client

Today, we are releasing em-eventsource, a EventMachine client for EventSource. Here’s a use-case:

require "em-eventsource"

EM.run do
  source = EventMachine::EventSource.new("http://example.com/streaming")
  source.message do |message|
    puts "new message #{message}"
  end
  source.start # Start listening
end

It handles all features of the current specification, except for the line separator, which can only be \n yet.

Why so? Quoting the spec:

Since connections established to remote servers for such resources are expected to be long-lived, UAs should ensure that appropriate buffering is used. In particular, while line buffering with lines are defined to end with a single U+000A LINE FEED (LF) character is safe, block buffering or line buffering with different expected line endings can cause delays in event dispatch.

Apart from this specific point, you can already use the gem and/or convert your old streaming API to a Server-Sent Events compatible one.

About cross-browser compatibility

EventSource is supported by:

  • Chrome 9
  • Firefox 6
  • Opera 11
  • Safari 5

You can also use some polyfills like jquery.eventsource if you want.

Have a comment? Contact me by email.