TP2 HTML5 2011-2012 M2 Miage

De $1

Version de 18:35, 23 Avr 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Introduction

Intégration de l'aspect "multi-participants"

Nous allons maintenant intégrer à notre projet un chat multi-participants utilisant l'api Web Socket. Pour ce faire, le code HTML5 à ajouter sera très simple, mais il faut avant tout installer un serveur web comprenant le protocole des Web Sockets. La page des ressources HTML5 recense des serveurs qui supportent cette feature (la liste est incomplète), mais pour ce TP nous allons nous servir d'un serveur embarqué très léger, qui a beaucoup de succès en ce moment, de par sa grande souplesse. Il s'agit du serveur NodeJS qui est écrit en Python, et qui permet d'écrire des applications web directement en javascript. il inclut l'interpréteur javascript le plus rapide du moment, nommé V8 (le même qu'il y a dans le navigateur Chrome). Le fait de pouvoir écrire des applications côté serveur en javascript est avantageux car les échanges de paramètres/valeurs de retour entre clients javascript s'exécutant dans le navigateur et appli serveur en javascript sont naturelles.

Un serveur web embarqué n'est pas censé tenir une grosse charge, fournir des services évolués de maintenance/déploiement/sécurité, etc... Il se trouve à l'opposé de ce que l'on appelle des "serveurs d'application" comme JBoss, Glassfish, WebSphere, Oracle Application Server, etc... Ici on veut un serveur qui se lance en une seconde, qui occupe très peu de mémoire, etc... Dans un autre TP de mon cours de M2 on a utilisé comme serveur embarqué le serveur Grizzly (qui est inclut dans GlassFish) mais nous n'avons pas réussi simplement à faire tourner une implémentation des WebSocket dessus (pourtant une telle implémentation existe, dans les night builds, etc.. mais c'est encore très nouveau...). Au passage, ce que j'ai dit au début de ce paragraphe n'est pas forcément vrai : NodeJS est ultra-performant en ce qui concerne la gestion de la charge car il utilise un modèle de programmation "par événement" et non pas un modèle classique à base de Threads. On en reparlera.

Outils à installer au préalable : Firebug pour Firefox

On ne peut faire de JavaScript et de développement web sérieux sans une console de debug. Si vous êtes fans de Firefox, récupérez Firebuf sur getfirebug.com. Une fois installé, redémarrez Firefox et tapez F12, la console de debug doit s'ouvrir. Pour Chrome il y a un équivalent par défaut : tapez ctrl-shif-i (windows, linux) ou ctrl-shift-j (mac). Sans ce type d'outils, vous ne pourrez pas debugger des erreurs JavaScript.

Installer le serveur Node.JS et le tester !

La procédure est simple : allez sur le site officiel de Node.JS : http://www.nodejs.org, selon que vous êtes sous windows, mac ou linux, suivez les instructions. Si vous êtes sur une distrib linux populaire comme Ubuntu, il existe des packages, cherchez l'existence d'un package NodeJS.

LINUX : ne prenez pas les sources, cliquez sur le lien pour recuperer directement les packages pour votre distribution :

Linux NodeJs.png

Pour info, sur le TP tout a été testé avec la version 0.6.8 mais il y a de bonnes chances pour que tout fonctionne avec des versions proches. Dans le pire des cas, sous linux, vous pouvez récupérer les sources, elles compilent statiquement.

  1. Ajoutez dans la variable PATH le chemin où NodeJs a été installé (par ex pour ceux qui sont sous Windows : C:\Program Files(x86)\nodejs),
  2. Ouvrez une fenêtre de terminal et tapez "node --version" ça doit afficher la version courante (0.6.8 à l'heure où j'écris ce TP). Si cela dit "command not found", alors vous n'avez pas bien positionné la variable PATH. Vérifiez, re-ouvrez une fenêtre de terminal, re-testez.

Testez maintenant une petite application, par exemple un micro serveur HTTP.

  • Créez le fichier test.js suivant :
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');

et que vous sauvez quelque part . Puis lancez (depuis la ligne de commandes) la commande suivante :

node test.js


Vous venez de lancer un serveur qui répond à des requêtes http sur l'URL suivant : http://localhost:8124 Essayez donc d'ouvrir cet URL avec un navigateur web ! Cela doit afficher :

Snap5.jpg

Le serveur est lancé !

Snap6.jpg

Le navigateur a eu une réponse ! Vous voyez le petit code javascript du fichier test.js, c'est déjà un serveur ! C'est cela, la magie d'un serveur embarqué !

Ajout de librairies pour les WebSockets

Les librairies pour nodeJS s'appellent des "modules". Il existe de nombreuses manières de les installer (notamment via le réseau et de manière globale au travers de  la commande "npm", le NodeJS Package Manager), mais nous allons faire le plus simple possible : les mettre dans un répertoire "node_modules" dans le répertoire où se trouvera votre TP.

Desarchivez cette archive :   ChatNowJs.zip (1.8 Mo) qui contient les modules nodeJS nécessaires aux websockets et à la manipulation simple d'un serveur web HTTP. Il s'agit des modules socket.io, express et nowJS. Ceci doit créer un répertoire "ChatNowJS" qui contiendra deux exemples de chat ainsi que les modules dont on vient de parler.

Si vous êtes sous Windows, sachez qu'on ne peut pas encore simplement utiliser le package manager car le module "nowJS" ne s'installera pas à cause d'un problème de compilation native qui est requise. Voici donc comment faire :

Si vous êtes sous Mac ou Linux, tapez simplement les commandes suivantes : "npm install socket.io", puis "npm install node-proxy" puis "npm install now", puis "npm install express". Si cela foire, ce n'est pas grave, les modules viennent aussi dans l'archive   ChatNowJs.zip (1.8 Mo)
 

  • Testez le chat le plus simple en lançant la commande "node simpleChat_server.js" et en ouvrant http://localhost:8080 dans un navigateur web, ouvrez deux onglets avec la même adresse. Vous ne devez pas avoir d'erreur au lancement du serveur. Si c'est le cas, vérifiez que vous avez toit bien installé.
     
  • Si vous n'avez pas d'erreur lors du lancement de la commande "node  simpleChat_server.js", mais que cela ne fonctionne toujours pas, regardez la console javascript ou la console d'erreur de Firebug (firefox). Si il y a un message "now.distributeMessage no such object/function", alors votre navigateur ne supporte pas les "bons websockets" ou bien vous avez un antivirus/antispyware/firewall qui les bloque. Vous pouvez, si vous n'arrivez pas à identifier ce qui les bloque, utiliser une solution de secours en indiquant à la librairie socket.io de ne pas utiliser les websockets html5. Ce la se fait en modifiant une ligne dans le code du serveur : il faut mettre var everyone = nowjs.initialize(server, {socketio: {transports: ['xhr-polling', 'jsonp-polling', 'htmlfile']}}); au lieu de var everyone = nowjs.initialize(server).

  • Maintenant que le chat fonctionne bien, regardez bien le code source htlml et js de cet exemple. La lirairie NowJS (voir  http://nowjs.com/) permet de partager des objets (attributs et methodes) entre le code qui tourne dans le navigateur et le code qui tourne sur le serveur. Magique ! Cette librairie utilise en coulisse la librairie socket.io (voir  http://www.socket.io) qui permet de faire des websockets avec des systèmes de rétro-compatibilité si le navigateur ne supporte pas les websockets.
     
  • Testez et étudiez le chat "multiroom" en lançant "node multiroomchat_server.js" et en ouvrant localhost:8080
     
  • Ceux qui veulent en savoir plus peuvent regarder les guides, démos et tutoriaux sur le site  http://nowJS.com

Ajout de la fonctionnalité "dessin à plusieurs" dans votre logiciel de dessin

Modification (toute petite) du code du serveur HTTP/websockets

Servir la page HTML avec une version à peine modifiée du code serveur du chat le plus simple. Voici un exemple de fichier que l'on appellera PaintServer.js

La principale différence réside dans la création du serveur HTTP, au début du source. On utilise le module "express" qui permet d'augmenter les possibilités du serveur web minimal précédemment vu. Ici il va servir la page index.htmlpar défaut mais surtout, si cette page inclut du javascript, des css ou des images, ces fichiers seront également servis par le serveur, avec les bons types mime.

// On va utiliser le module express qui permet de faire un serveur 
// web plus complet, capable de servir une page par defaut,
// des pages qui contiennent des css, qui incluent des fichiers 
// javascript etc
var express = require('express');  
  
// Création du serveur, page par defait, port
var app = express.createServer();  
app.configure(function(){  
  app.use(express.static(__dirname + '/'));  
});  
app.get('/', function(req, res, next){  
  res.render('index.html');  
});  
app.listen(8080);  
  
// Création d'un serveur de socket via nowJS  
var nowjs = require("now");  
var everyone = nowjs.initialize(app);  
  
  
nowjs.on("connect", function(){  
  console.log("Joined: " + this.user.clientId);  
});  
  
nowjs.on("disconnect", function(){  
  console.log("Left: " + this.user.clientId); 
});  
  
// Fonction qui renvoie un message à tout les clients,
// en appelant la fonction receiveMessage définie dans
// les clients  
everyone.now.distributeMessage = function(message){
  everyone.now.receiveMessage(this.now.name, message);
};

Intégration du chat dans le paint et utilisation du chat pour broadcaster les ordres de dessin

Vous allez maintenant utiliser le chat que nous venons d'étudier pour transférer des objets d'un client de paint vers tous les autres. Pour cela, vous pouvez utilisez les fonctions de sérialisation de JSon de javascript et de jQuery.

Première étape : faire marcher le chat dans le fichier HTML du paint du TP1

Commencez par prendre les morceaux nécessaires du fichier html du SimpleChat.html et fusionnez-les avec le fichier example5.html (que je vous conseille de renommer maintenant en index.html, il marchera directement avec le code du serveur ci-dessus). 

  • Inclure dans le header les lignes qui incluent now.js et jquery-min.js,
  • Ajouter dans le header le code javascript qui est dans une balise script,
  • Ajouter les éléments HTML du chat, les champs de saisie etc.
  • Lancer "node PaintServer.js" et ouvrir "localhost:8080", le chat et le paint doivent fonctionner. Vérifier avec la console d'erreur qu'il n'y a pas d'erreurs.

Deuxième étape : basculer le script du paint dans le fichier JavaScript du paint

Recopiez donc tout à la fin du fichier example5.js le code de chat (la partie entre les balises script), que je vous conseille maintenant de renommer en paint.js.

Relancez le serveur, retestez, vérifiez que tout fonctionne. Maintenant il sera possible d'envoyer des messages depuis les fonctions de dessin et inversement, de dessiner à réception d'un message.

     
$(document).ready(function(){
  now.receiveMessage = function(name, message){
    $("#messages").append("<br>" + name + ": " + message);
  }
  
  $("#send-button").click(function(){
    now.distributeMessage($("#text-input").val());
    $("#text-input").val("");
  });

  now.name = prompt("What's your name?", "");

});

Troisième étape : envoyer des messages lorsqu'une droite est dessinée, un cercle, etc...

Envoyez  via le chat les événements de dessin sous forme de texte, et vérifiez qu'ils transitent bien ! Par exemple "j'ai dessiné une ligne de telle coordonnées à telles coordonnées", vérifiez que le texte a bien transité vers tous les clients. L'envoi se fait en général juste avant les img_update() qui effectuent le dessin. Vérifiez que les messages passent bien par le chat.

Quatrième étape : envoyer des objets en JSON

  1. Maintenant, essayez d'envoyer un objet Javascript sérialisé en JSon, et décodez-le à l'arrivée, affichez un message dans le texte du chat correspondant à l'objet décodé. rappel : lorsque nous transmettrons réellement ces objets, on les mettra au format JSON à l'aide de la fonction JSON.stringify(message) de JavaScript, côté récepteur, on transformera les objets JSON reçus en objets javascript à l'aide de la fonction http://api.jquery.com/jQuery.parseJSON/ de jQuery (ce qui est plus simple qu'utiliser la fonctuon JavaScript pure JSON.parse(jsonObject)
     
  2. Interprétez-les quand ils sont reçus et provoquez le dessin côté récepteur du dessin effectué par l'envoyeur. Vous aurez peut être besoin de modifier un peu le format de vos objets pour qu'ils soient plus faciles à manipuler.

Exemple de transformation objet javascript-> json et envoie par websocket

var objJSON = { "type" : 'line', "x0" : tool.x0, "y0" : tool.y0,"x1" : ev._x, "y1" : ev._y };
var msgJSON = JSON.stringify(objJSON);
now.distributeForm(msgJSON);

JSON -> objet javascript

// lorsqu'on reçoit un message en JSON
now.receiveForm = function(name, msgJSON){
objJSON = jQuery.parseJSON(msgeJSON);
...
if(objJSON.type == "Line"){

 Cinquième étape : faites du dessin quand un message JSON arrive

Maintenant, il faut détecter quand on reçoit une message de dessin, et effectuer le dessin !