Real-Time Facebook-like Badges Using Pusher and Badger

We have been tasked with the development of a large facilities management application -- one which has gone through several revisions over the years. In moving the project forward we wanted to add in features that provide more information quickly, and at-a-glance. In order to make things more real-time we investigated several options for replicating Facebook-style "badges" that would let users know when they had new tasks assigned to them or other content alerts that needed their attention.

AJAX, Long Polling, Comet, and Pusher (Now Dasher, now Dancer, now Prancer and Vixen!)

When we started doing our research we came across several different server technologies that had various pros and cons. We investigated rolling our own Comet solution which would give us the most flexibility for the lowest cost. However, the server resources necessary for a properly scalable real-time notification system outweighed the benefits that we could have gained from it. Ultimately we landed on Pusher, a third-party web service that handles the heavy-lifting of real time push notifications and does so with aplomb.

Pusher requires you to set up a (free) account with which your real-time notifications will be processed. Their sandbox account gives you plenty of room to test on a development application before springing for the reasonable monthly fees once you're ready to go live. When you create an account you'll receive three keys: an API ID, an app key and an app secret, all of which will be used in your code.

Initial Setup - Get the Code

There are two components to this process: a client-side jQuery and a server-side PHP function. If you don't already have it make sure you download jQuery itself though you may have already loaded this if you're working on an existing application. Then download the PHP library from Pusher.com (you can just hotlink the necessary jQuery library from Pusher.) In order to create and style the notification badges you'll also need the Badger jQuery plugin as well. So download all of those and save them to your web server. Then add the necessary links to the HEAD of your HTML document like so:

<script type="text/javascript" src="/scripts/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="http://js.pusher.com/2.1/pusher.min.js"></script>
<script type="text/javascript" src="/scripts/badger.min.js"></script>

Client Side jQuery

If you want the notification system to be available wherever the user is on your application then you'll need to include the pusher jQuery code on every page. Here's what it looks like and then I'll explain what each piece does:

<script type="text/javascript">
var pusher = new Pusher('<?php print PUSHER_APP_KEY; ?>', { authEndpoint: \'/pusher_auth\' });
var channel = pusher.subscribe('private-<?php print $user['0']['uid']; ?>');
channel.bind('notification', function(data) {
  $('#nav_main').badger(data.message);
});
</script>

The first line declares a new pusher object using your PUSHER_APP_KEY and it also includes a link to another PHP page which I've called pusher_auth. This page, which we'll create later, handles the authentication necessary for private pusher channels. Without going into great detail, private channels are necessary so that your users can only see the notifications assigned to them. Moving on, the next line subscribes the active user to a private channel with the "private-" prefix, followed by their user ID. Your system may vary depending on how you're managing your users but ultimately you'll be creating a private channel for each user in your system. How you choose to make those unique is up to you. The next line binds the pusher "notification" action (which we'll create later) to a jQuery response -- in this case, it's to apply the Badger plugin to the #nav_main DIV using the message that the pusher notification sends.

Authenticating Private Channels

As I mentioned before, the concept of private channels simply keeps the notifications separate for your users. But we do need a way to make sure that the end user isn't viewing the notifications of another, and that's where the authEndpoint comes in. A private channel passes two $_POST variables that we can use to ensure the user is legitimate. Here's the code, explanation to follow:

include $_SERVER['DOCUMENT_ROOT'] . '/includes/pusher.php';
if ($user['0']['uid'] == substr($_POST['channel_name'], 8)) {
  $pusher = new Pusher(PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_ID);
  echo $pusher->socket_auth($_POST['channel_name'], $_POST['socket_id']);
}
else
{
  header('', true, 403);
  echo "Forbidden";
}

After including the necessary PHP pusher library that was downloaded from pusher.com, the if/then statement simply checks the logged in user ID against the submitted channel name by subtracting the characters "private-", leaving just the user ID behind. Again, adjust this to match your application's user authentication system. Assuming it passes, we then instantiate a pusher object using the PHP library and supply the necessary keys. Once that's done the next line executes the socket_auth method using the submitted $_POST variables in a hash which is in turn returned to the calling jQuery page that we wrote earlier.

Trigger an Event

At this point your application is now ready and waiting for requests to come through from Pusher. So how do we fire off a request? Well, that depends on what it is you want to alert. In our case we wanted to send a badge every time a user was given a new task to complete in our custom process tracking system. We did it by creating a function which we can then call any time something happens that demands an alert:

function send_pusher_notification($uid, $items = 1) {
  include $_SERVER['DOCUMENT_ROOT'] . '/includes/pusher.php';
  $pusher = new Pusher(PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_ID);
  $pusher->trigger('private-' . $uid, 'notification', array('message' => '+' . $items));
}

Again, we include the necessary PHP library and create the $pusher object using our keys but the last line is where the magic happens. The function accepts the user's id and the number of notifications by which to increment the counter. The trigger method is passed the name of the channel (the user's ID prefixed with "private-") along with the type of event, in this case "notification" as that's the only one we've created, followed by the number of items in an array. Pusher BadgesThe jQuery function that we created first will accept that parameter and then display the necessary badge. The nice thing about the Badger jQuery plugin is that it's extremely simple to trigger -- passing +2 for example, will increment an existing badge by 2 or create a new one with the number 2 so you don't have to worry about if/thens to see if a badge exists or not.

And that's about all there is to it. You can use the CSS included with the Badger plugin or style the resulting HTML your own way. We found that the badges were a bit large for our taste so we made some CSS changes but that's purely optional.

Comments

This Is a well Post.

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
3 + 5 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.

Questions?

Do you have a question about something you saw here in our blog? Are you interested in a custom website for your business? If so, please contact us here.