HTML5 & Web socket

HTML5

HTML5 apporte beaucoup au développeur en permettant de donner plus de sens à la source.

Tout d'abord de nombreux nouveaux tags sont désormais valides header, nav, footer, etc... et permettent une meilleure sémantique des pages. Ensuite, tous les tags HTML peuvent avoir des attributs personnalisés liés à l'application et suffixé de data-. On trouvera donc data-monAttribut plutôt que d'utiliser une classe inutile et dénuée de sens.

Exemple de code HTML5

<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" media="screen" href="ecran.css"> </head> <body> <header> <h1>Wake up sheeple!</h1> <p><a href="news.html">News</a> - <a href="blog.html">Blog</a> - <a href="forums.html">Forums</a></p> <p>Last Modified: <time>2009-04-01</time></p> <nav> <h1>Navigation</h1> <ul> <li><a href="articles.html">Index of all articles</a></li> <li><a href="today.html">Things sheeple need to wake up for today</a></li> <li><a href="successes.html">Sheeple we have managed to wake</a></li> </ul> </nav> </header> <div> <article> <header> <h1>My Day at the Beach</h1> </header> <div> <p>Today I went to the beach and had a lot of fun.</p> ...more content... </div> <footer> <p>Posted <time pubdate="" datetime="2009-10-10T14:36-08:00">Thursday</time>.</p> </footer> </article> ...more blog posts... </div> <footer> ... </footer> </body> </html>

Les APIs

De plus, HTML5 apporte une suite d'API intéressantes pour rendre les applications web encore plus performantes, indépendantes, etc :

Stockage en local de fichier

Base de données locales et accessible dans une pseudo version de SQL

Stockage de données indexée (sous la forme d'arbre)

Manipulation de fichier

Capture de données sur le device (vidéo / photos)

Push events

Les websockets

Géolocalisation

Web Workers (exécution de tâches de fond)

Mode déconnecté

Références

http://www.html5rocks.com/

http://slides.html5rocks.com/

L'interface WebSocket

L'interface proposée par le consortium W3C convernant les websockets est disponible à l'adresse: http://dev.w3.org/html5/websockets/

Elle est encore à l'état de draft (état au 24 mai 2011) mais certains navigateurs l'implémente d'ores déjà; à savoir Chrome et Safari (y.c. la version mobile).

L'interface proposée par le W3C se présente de la manière suivante:

interface WebSocket { readonly attribute DOMString url; // ready state const unsigned short CONNECTING = 0; const unsigned short OPEN = 1; const unsigned short CLOSING = 2; const unsigned short CLOSED = 3; readonly attribute unsigned short readyState; readonly attribute unsigned long bufferedAmount; // networking attribute Function onopen; attribute Function onmessage; attribute Function onerror; attribute Function onclose; readonly attribute DOMString protocol; void send(in DOMString data); void close(); };

Côté serveur

Dans le cadre des quelques démonstrations qui vont suivre, nous allons utiliser une librarie php disponible sur github. Toutefois, il existe déjà d'autres implémentations de serveur websockets en Java, en Ruby,...

Côté client

Afin de pouvoir satisfaire tout le monde (c-à-d ceux qui n'utilisent pas des browser modernes Safari ou Chrome :) ), il est possible d'établir une connexion persistante entre le serveur et ces clients via un fichier swf. Par contre, l'utilisation de cette méthode nécessite l'ajout de quelques classes et fichiers pour le client.

Exemples

1 - Date like in ajax

Lien sur l'application

Description

Le fonctionnement de cette application permet de faire la transition entre les requêtes ajax et les websockets.

Pour ce faire, on va établir une connexion persistante entre le client et le server mais les données ne transiterons qu'à la demande du client. Lorsque le client appellera le serveur, celui-ci lui renverra l'heure actuelle et elle sera ensuite affichée chez le client.

Coté Client

Dans cet exemple, le code javascript est très simple. On va créer un nouvel objet WebSocket fourni par l'API du browser et ne fonctionnera que sur Chrome, Safari et Safari mobile.

var myWebsocket = new WebSocket(wsUri);

Le reste du code va simplement permettre de définir les méthodes onopen, onclose, onmessage et onerror de l'objet websocket. On peut noter que la grande partie du code est utilisé pour l'esthétique de l'interface.

myWebsocket.onopen = function (evt) { console.log('Websocket open.'); $('#status').removeClass().addClass('online').html('online'); writeToScreen('connected to '+ wsUri) $('#send').attr('disabled', false); } myWebsocket.onclose = function(evt) { console.log('Websocket closed.'); $('#status').removeClass().addClass('offline').html('offline'); $('#send').attr('disabled', true); } myWebsocket.onmessage = function(evt) { console.log('Message received.') writeToScreen('Received: ' + evt.data); output.animate({scrollTop: output.attr('scrollHeight')}) } myWebsocket.onerror = function(evt) { console.error('Error') $('#status').removeClass().addClass('error').html('error'); }

Côté serveur

Du point de vue du serveur, tout est très simple. Nous avons enregistré une nouvelle application et avons définis quelques méthodes au sein de celle-ci. Cette application va gérer la (dé)connexion des clients et leur répondre la date uniquement à leur demande.

class DateApplication extends Application { private $clients = array(); private $lastTime = 0; public function onConnect($client) { $this->clients[] = $client; } public function onDisconnect($client) { $key = array_search($client, $this->clients); if ($key) { unset($this->clients[$key]); } } public function onData($data, $client) { $client->send(date(DATE_RFC822)); } }

2 - Date from server

Lien sur l'application

Description

Le fonctionnement de cette application diffère de l'exemple précédent. Cette fois-ci, c'est le serveur qui va interagir avec le(s) client(s) connecté(s). Lors de l'ouverture de l'exemple, l'application va ouvrir une connexion sur le serveur. Celui-ci va enregistrer le client dans une liste puis, toutes les 3 secondes, le serveur va transmettre la date à tous les clients

Coté Serveur

public function onTick() { if (time() >= $this->lastTime + 3) { $this->lastTime = time(); foreach ($this->clients as $sendto) { $sendto->send(date(DATE_RFC822)); } } }

3 - Simple IRC

Lien sur l'application

Description

Cet exemple a pour but de créer un mini chat. Il faut alors que le serveur soit en mesure :

D'enregistrer les nouveaux clients.

Broadcaster l'arrivée de quelqu'un.

Broadcaster les messages des utilisateurs

De leur côtés, les clients doivent être en mesure de :

Effectuer une connexion au serveur

Transmettre des messages à tout le monde

Récupérer les messages

Côté Client

var wsUri = "ws://monserveur:monport/echo"; var output; $(document).ready(function() { output = $("div#log"); initWebSocket(); $('#send').click(function(){ console.log('Message sent: ' + $('#message').val()); writeToScreen("Websocket called"); websocket.send($('#message').val()); }); }); function initWebSocket() { websocket = new WebSocket(wsUri); websocket.onopen = function (evt) { console.log('Websocket open.'); $('#status').removeClass().addClass('online').html('online'); writeToScreen('connected to '+ wsUri) $('#send, #message').attr('disabled', false); } websocket.onclose = function(evt) { console.log('Websocket closed.'); $('#status').removeClass().addClass('offline').html('offline'); $('#send, #message').attr('disabled', true); $('#connection').text('Connect'); setTimeout(initWebSocket, 1000); } websocket.onmessage = function(evt) { console.log('Message received.') var data = JSON.parse(evt.data); writeToScreen('['+data.who+']: ' + data.msg); output.animate({scrollTop: output.attr('scrollHeight')}) } websocket.onerror = function(evt) { console.error('Error') $('#status').removeClass().addClass('error').html('error'); } } function writeToScreen(message) { var pre = document.createElement("pre"); pre.style.wordWrap = "break-word"; pre.innerHTML = message; output.append(pre); }

Côté Serveur

public function onData($data, $client) { foreach ($this->clients as $sendto) { $obj = (object) null; $obj->who = $client->toString(); $obj->msg = $data; $sendto->send(json_encode($obj)); } }

4 - IRC (all browser compliant)

TO BE COMPLETED

Les exercices

Hash me!

En se basant sur l'exemple 1 et en modifiant ex-hash-template.zip, faire en sorte que le client envoie une chaine de caractères au serveur. Celui-ci lui renverra le hash md5 de la valeur au client qui l'affichera.

IRC++

En partant de ex-irc-template.zip et de l'exemple 3, faire en sorte que :

Les clients ne reçoivent pas leurs propres message. Il sera toutefois afficher lors de l'envoie par le JS.

Les clients peuvent mettre à jour leur nom d'utilisateur. Celui-ci sera transmis dans la liste des utilisateurs

Les clients reçoivent et mettent à jour la liste des personnes connectées uniquement lorsque cela est nécessaire