Tuesday, March 11, 2014

How to send real time notifications to your Drupal site users

Often you would want to notify logged in users of an urgent deployment that is going to take the site down. For these unavoidable deployments, real-time notifications to end users would be God-send as it would help editors save their work (if they are adding content) in adequate time.

Here is a simple attempt at building one such system. HTML5 Server Sent Events is a one way communication technology which we can leverage for this. The caveat is that editors need to use HTML5 browsers or resort to XHR polling.

In this example, we are using Jenkins for deployment and want to notify logged-in site editors when a deployment is about to happen. We'll build a separate notification server for this purpose (on node.js) that will register browser connections and will also listen for notifications from Jenkins. Once it receives a notification regarding a deployment, it will broadcast that to the registered browsers. We'd like this server to support different sites and their notifications (multi-site scenario in Drupal). Jenkins can send build info notifications via the Notifications plugin. This server has been built and hosted on GitHub along with usage instructions.

When each browser gets loaded, it fires off an EventSource() to the server, registering its connection. The server keeps a list of active connections per site. The Notifications plugin on Jenkins posts JSON build information to our server as it happens, with the site information as parameter. The server in turn broadcasts this to the registered browsers for that site, who then get a Growl/Ubuntu like notification. The GitHub repo contains both the server side code (node.js) and client side javascript with the required polyfill, which can be used for any web application.

To get the client-side working in Drupal, read on.


Create a module that adds the client JS and CSS on all pages. It would help to create and use a permission to receive notifications for editors and other roles. Some of the crucial hooks are listed below. The JS assets are loaded on hook_init() based on 'receive sse notifications' permission. For the Growl-like notifications, add in some required bit of html in hook_preprocess_page() which invokes a theme function so as to make it extensible/over-writeable.

/** * Implements hook_init(). */ function mymodule_init() { if (user_access('receive sse notifications')) { drupal_add_js(SSECLIENTPOLYFILLPATH, 'external'); drupal_add_js(variable_get('mymodule_eventsource_url', SSECLIENTJSPATH), 'external'); // Jquery notify additions // See http://www.erichynds.com/blog/a-jquery-ui-growl-ubuntu-notification-widget drupal_add_css(drupal_get_path('module', 'mymodule') . '/assets/css/ui.notify.css'); drupal_add_js(drupal_get_path('module', 'mymodule') . '/assets/js/jquery.notify.js'); // Add the notifications server URL for the SSE client JS to use. drupal_add_js(array( 'mymodule' => array( 'server' => variable_get('mymodule_server_address', SSESERVERPATH) ) ), 'setting'); } }
/** * Implements hook_permission. */ function mymodule_permission() { return array( 'receive sse notifications' => array( 'title' => t('Receive HTML5 SSE notifications'), 'description' => t('Receive notifications regarding site builds in real-time.'), ), ); } /** * Implements hook_theme. */ function mymodule_theme() { return array( 'mymodule_jquery_notify' => array( 'variables' => array(), 'template' => 'jquery_notify', 'path' => drupal_get_path('module', 'mymodule') . '/templates', ) ); } /** * Implements hook_preprocess_page(). */ function mymodule_preprocess_page(&$variables) { if (!user_access('receive sse notifications')) { return; } // Append notify container to footer or content. if (!empty($variables['page']['footer'])) { $variables['page']['footer']['jquery_notify']['#markup'] = theme('mymodule_jquery_notify'); } else { $variables['page']['content']['jquery_notify']['#markup'] = theme('mymodule_jquery_notify'); } }

No comments: