I've been working more with Ruby lately, and wanted to implement a Ruby real-time messaging project like the one in my previous post. I decided on Faye, because its features seemed to match Socket.IO's pretty closely (subscriptions and transport fallbacks, in particular).
I initially ran into some confusion after working with Socket.IO, mostly because I had the false impression that Socket.IO was a synonym for WebSockets. I was wrong about that!
Socket.IO != WebSockets
WebSockets are only a method of transporting data over the web, and both Socket.IO and Faye built a WebSocket-compatible framework on top of it. These frameworks include subscribing to certain messages or events, as well as fallbacks for browsers without WebSocket support.
Faye was more complicated to get up and running than Socket.IO, but that could be attributed to my level of Ruby knowledge. It requires separate instance of Ruby, while you can serve Socket.IO on the same instance of Node.js as your application. You also have to run Faye with thin
in production mode.
It was also a bit more difficult to see what was going on behind-the-scenes with the Faye browser client. In particular, I wanted to verify that Faye was using the WebSockets, intead of long-polling or another fallback.
It was easy to see the Socket.IO client's socket.opts.transports
property in Firebug, but it took me a lot of searching to figure out how to see the Faye client's detailed information. I finally came across a forum thread that mentioned using Faye.logger = window.console
. You wouldn't use this in a live environment, but it lets you see detailed output about the Faye client for debugging.
Enough talk, here's some code
faye.ru
require 'faye'
Faye::WebSocket.load_adapter('thin')
faye = Faye::RackAdapter.new(:mount => '/faye_server', :timeout => 5)
run faye
Run the following command to start the Faye instance: rackup faye.ru -s thin -E production
app.rb
require 'sinatra'
require 'eventmachine'
require 'faye'
client = Faye::Client.new('http://localhost:9292/faye_server')
post '/user/:id' do
# do work here
message = client.publish("/messages/#{params[:id]}", "UserUpdated")
content_type :json
{ "message": "User update accepted" }.to_json
end
Run this Sinatra API: ruby app.rb
index.html
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="http://localhost:9292/faye_server/client.js"></script>
<script>
$(document).ready(function() {
var client = new Faye.Client('http://localhost:9292/faye_server');
var user = '12345';
client.subscribe('/messages/' + user, function(data) {
console.log("Faye: " + data);
//perform an action based on the data content
});
});
</script>
Finally, go to index.html
in your web browser and open up the JS console. Using your favorite REST client, send a POST
to http://localhost:4567/user/12345
. You should see a Faye: UserUpdated
message show up in your browser's JS console.