Skip to content

PrivatePub

Seth Vargo edited this page May 6, 2012 · 1 revision

PrivatePub is a Faye extension for Rails. It makes server-client communication significantly easier by maintaining an open websocket to the client. It also provides various channels and supports a variety of protocols.

What's it do?

In short, Envelope uses PrivatePub to publish important or informational messages back to the client.

{{{ napkin title Client-Server Flow (Faye) Client->Server: Enqueue a Job (load messages) note right of Server: DelayedJob processes in background Server->Client: JSON response }}}

Through our various phases of user-testing, we found that system-feedback was absolutely crucial to the user. PrivatePub provides a way for our "backend" to alert the "frontend" when something happens.

For example, when a message is retrieved, it all happens in the background (in a separate thread and worker process), so not to tie up the Rails environment. However, since we are outside of the Rails environment, there's no way to directly communicate back to the frontend. With PrivatePub, we can publish_to the given user's channel. The frontend listens on this channel and requests are handled by the PrivatePubHandler class. Once that message is loaded, we can push the message (as JSON) to the frontend and have it magically populate before the user.

Technical Details

All users are assigned a unique queue_name. On the initial page load, a subscription is made to the user's queue. From this point forward, all information pushed to the user's queue is received by the frontend.

- if logged_in?
  = subscribe_to current_user.queue_name

  :javascript
    $(function() {
      new PrivatePubHandler("#{current_user.queue_name}");
    });

At first iteration, there was no clean way to handle all possible callbacks/messages coming in on the user's channel. However, with the aid of coffeescript, we created a PrivatePubHandler.coffee file for handling all our requests.

When PrivatePub receives a signal, that message is passed off to the handler. The handler decides how/what to do with the message. This allowed us to keep all the private_pub callbacks in a single file.

class PrivatePubHandler
  constructor: (@queue) ->
    PrivatePub.subscribe @queue, (data, channel) =>
      @[data.action](data)