The latest iteration of faye-websocket has just been released for Ruby and Node, probably the last release before I get back to making progress on Faye itself. It contains two major new features: EventSource support, and support for the Rainbows and Goliath web servers for the Ruby version.
EventSource is a server-push protocol that’s supported by many modern browsers. On the client side, you open a connection and listen for messages:
var es = new EventSource('http://example.com/events');
es.onmessage = function(event) {
// process event.data
};
This sends a GET
request with Content-Type: text/event-stream
to the server
and holds the connection open, and the server can then send messages to the
client via a streaming HTTP response. It’s a one-way connection so the client
cannot send messages to the server over this connection; it must use separate
HTTP requests. However, EventSource uses a much simpler protocol than WebSocket,
and looks more like ‘normal’ HTTP so it has less trouble getting through
proxies.
On the server side, supporting this requires a lot of the same code as WebSocket, and I might use it in Faye later on, so I decided to add support for it in faye-websocket. In your Rack app, you can now easily handle EventSource connections using an API similar to WebSocket:
require 'faye/websocket'
App = lambda do |env|
if Faye::EventSource.eventsource?(env)
es = Faye::EventSource.new(env)
# Periodically send messages
loop = EM.add_periodic_timer(1) { es.send('Hello') }
es.onclose = lambda do |event|
EM.cancel_timer(loop)
es = nil
end
# Async Rack response
es.rack_response
else
# Normal HTTP
[200, {'Content-Type' => 'text/plain'}, ['Hello']]
end
end
Just like WebSocket
, EventSource
is designed as a convenient wrapper around
the Rack environment and underlying TCP connection that deals with the wire
protocol and connection details for you. It tries not to make any assumptions or
force constraints on your application design. There are a lot of WebSocket
libraries around whose interfaces look more like Rails controllers; black-box
Rack components or full-stack servers that hide the socket object and force you
respond to WebSockets on one endpoint, and normal HTTP on another. Faye needs to
be able to speak many different transport protocols over a single endpoint,
which is why this library is designed to be usable inside any Rack adapter while
leaving routing decisions up to you.
The benefit of interacting with the sockets as first-class objects is that you
can pass them to other parts of your application, which can deal with them as a
simple abstraction. For example, if your application just needs to push data to
the client, as many WebSocket apps do, you can maintain a socket pool full of
objects that respond to send()
. When the application wants to push data, it
selects the right connection and calls send()
on it, without worrying whether
it’s a WebSocket or EventSource connection. This gives you some flexibility
around which transport your client uses.
The Node API to this is very similar and both are fully documented on GitHub: Ruby docs, Node docs.
The final big change is that the Ruby version now works under a broader range of web servers; it now supports Rack apps running under Thin, Rainbows and Goliath. Hopefully, providing a portable socket implementation that’s easy to drop into any Rack app will open up possibilities for more portable async app frameworks, decoupling the application from the network transport just as Rack did for HTTP. faye-websocket extracted its initial Thin and Rainbows adapters from the Cramp project, and there’s a chance Cramp can now remove its WebSocket code and rely on a simple abstraction for binding the app framework to the web.
As usual, download from Rubygems and npm, and get on the Faye mailing list if you have problems.