Real-time display of server push data using Server-Sent Events (SSE)

You are viewing revision #5 of this wiki article.
This is the latest version of this article.
You may want to see the changes made in this revision.

« previous (#4)

  1. Server push technologies
  2. Where's the demo?
  3. Browser support aka does it work in IE?
  4. So should we drop it until IE and Android support it?
  5. More information
  6. Version française

Server push technologies

There are several methods and techniques that come handy in the case you need to call an external resource periodically or if you are waiting for a server push, but I present here an easy and straightforward one using HTML5's Server-Sent Events (SSE).

Let's say you have an internal messaging system in your webapp, and you want to display messages dynamically and real-time to the relevant recipients.

Where's the demo?

No demo :-) But here are really easy steps to get it, and get it done.

Table structure

Let's keep things simple, we'll have a standard User model that is not represented here, and a Message model based on the following table structure:

[sql]
CREATE TABLE `Message` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `toUserId` int unsigned NOT NULL,
  `message` text NOT NULL,
  `new` tinyint NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `toUserId` (`toUserId`)
);
View

Say you want messages to show in any part of the webapp, so you can add an empty div to your main layout and a simple jQuery snippet firing the SSE call, like this:

<?php
Yii::app()->clientScript->registerScript('message-update', '
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource("' . CController::createUrl('site/getMessage') . '");
    source.onmessage = function(event) {
        $("#message").prepend(event.data).fadeIn(); // We want to display new messages above the stack
    };
}
else {
    $("#message").replaceWith("<div class=\"flash-notice\">Sorry, your browser doesn\'t support SSE.<br>Hint: get a real one :-)</div>"); // Don\'t be desperate, we\'ll see what we can do for you at the end of the wiki
}
', CClientScript::POS_READY);
?>
<div id="message"></div>
Controller (SiteController.php)

The app logic will be in our Site controller. The getMessage method will check at a defined interval (see below) whether there is any new message, and return a ready-to-display block that will be prepended to our message div.

So here's our controller method. Notice that you need to add the relevant access rule(s) for that method.

<?php
class SiteController extends Controller
{
    …
    /* Add access rules if needed for getMessage */public function actionGetMessage()
    {
        $messageList = Message::model()->findAll(array(
                            'condition' => 'toUserId = :myId AND new = 1',
                            'order' => 'id DESC',
                            'params' => array(':myId' => Yii::app()->user->_id)
                        ));
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache');
        echo "retry: 10000\n"; // Optional. We tell the browser to retry after 10 seconds
        if(count($messageList)) {
            foreach($messageList as $key => $message) {
                echo "data: <p>" . $message->message . "</p>\n";
            }
            //Now we run a bulk update query in order to flag the just retrieved messages (new = 0)
            $sql = 'UPDATE Message
                        SET new = 0
                        WHERE toUserId = ' . Yii::app()->user->_id;
            $command = Yii::app()->db->createCommand($sql);
            $command->execute();
        }
        flush();
    }
    …
}
?>

As you can notice, it's not real real-time, but a regular check at 10 second intervals. That is an optional parameter that falls back to the browser default if not specified.

Of course, the Message table update should be more accurate: with the above simplistic code, some messages could have been posted to the user during the method execution, so they would be flagged —wrongly— whatsoever.

Browser support aka does it work in IE?

Internet Explorer and Android browser (all versions) don't support Server-Sent Events out of the box. Neither do older versions of Firefox (< 6), Chrome (< 6), Safari (< 5), iOS Safari (< 4), or Opera (< 11).

So should we drop it until IE and Android support it?

It's up to you. There's a polyfill that gives SSE/EventSource support to IE 8+ and Firefox 3.5+.

More information

Read more about SSE and Websockets and other techniques:

Version française

Tutoriel Yii : Affichage en temps réel de données en provenance du serveur à l’aide des Server-Side Events (SSE)

9 0
17 followers
Viewed: 64 410 times
Version: Unknown (update)
Category: How-tos
Written by: bennouna
Last updated by: bennouna
Created on: May 3, 2012
Last updated: 11 years ago
Update Article

Revisions

View all history

Related Articles