Partage
  • Partager sur Facebook
  • Partager sur Twitter

Node.js : Mes expérimentations

Sous linux Ubuntu

    18 août 2010 à 19:03:12

    Bonjour à tous,

    Je viens à vous avec ce message pour faire un petit compte rendu de mes premières expérimentations de Node.js. Mon objectif était de réussir à maîtriser la bête, et de produire une application concrète. Ayant surtout envie de m'atteler aux sockets, je me suis donc attaqué à un chat. La source du serveur final, ainsi que les liens des différents modules, vous sont donnés à la fin du message.

    Installation



    L'installation a été la phase la plus simple. Il suffit d'aller sur http://nodejs.org/, de télécharger la dernière version, et de faire les habituels ./configure, make et make install.
    Pour exécuter un script, il suffit de taper "node monscript.js"
    Bref, très facile à utiliser.

    Le serveur HTTP



    La première étape a été de créer un serveur HTTP standard, qui gère les appels à des pages html et js. Assez simple, puisqu'il suffit de se servir du module "url" inclu dans Node.js pour parser la requête.

    Le serveur de socket



    Là ça a été un peu plus compliqué. A la base, je voulais me servir du module io.js. Mais celui-ci semble abandonné puisque même son site web est HS. Je me suis donc rabattu sur socket.io.js qui, sur le papier, avait l'air prometteur. En plus, il est fourni avec une démo de chat, pile poil ce qu'il me fallait.
    Le gros avantage de ce module, c'est qu'il propose un script serveur pour les socket, mais également le script client, qui tente par 5 méthodes différentes d'entrer en communication avec le serveur (websocket, flash, xhr-multipart, xhr-pollong et htmlfile). Ce qui rend le script assez accessible.

    En théorie, ça fonctionne bien et s'implémente facilement. Sauf qu'il m'a fallu plus d'une heure avant de comprendre que la méthode flash ne marchait pas chez moi, et bloquait le script. Comme il est possible de préciser les méthodes de communication souhaitées, j'ai juste enlevé le flash et c'est passé tout seul.

    Je me retrouve donc avec un chat en socket, qui utilise le même port que le serveur HTTP. Du pur bonheur.

    Les sessions



    Après quelques essais, je me rend compte que le fait d'actualiser la page créé systématiquement un nouveau client pour la socket, au lieu de reprendre l'ancien. Il m'a donc fallu trouver un module de gestion des session, pour attacher la socket au client. Aimant aller au plus simple, j'ai choisis Sessions.js.

    Là j'ai carrément déchanté. Le module n'est plus entretenu depuis 2009, et utilisait une version maintenant dépréciée de Node.js. Il m'a donc fallu le réécrire, quasiment en entier, pour le mettre à jour avec la version actuelle. J'ai un peu galéré, mais j'ai fini par y arriver. Mon chat retient donc la socket en fonction du client, et surtout le pseudo rentré.

    Il ne me restait qu'un seul problème : afficher le pseudo après un F5. Ne voyant pas trop comment faire, à part en y allant à coup de runat="server", je me suis naturellement tourné vers :

    Un moteur de template



    J'avoue qu'implémenter un moteur de template juste pour afficher un pseudo, c'est un peu excessif. Mais je me suis dit que, tant qu'à faire, ça me préparerait le terrain pour plus tard. Me voilà partir à la recherche d'un module. Certains m'ont paru assez sympas, tels que JSON Template, mais trop limités. Et d'autres ne me plaisaient pas dans leur façon de faire, comme node-template ou template.node.js. J'ai finalement choisis normal-template, qui reprenait la notation JSON.

    normal-template fourni également une démo, mais qui ne marche pas. Il utilise des méthodes dépréciées de Node.js. Du coup, me voilà reparti dans l'édition de la source. Une fois satisfait, il me reste à modifier le serveur HTTP pour qu'il passe par le moteur de template, et le tour est joué.

    Ressources



    Au final, je me retrouve donc avec un chat, sur un serveur HTTP gérant les requêtes HTTP standards et les sockets sur le même port. Il gère les sessions et utilise un moteur de template.
    Sans plus attendre, voici les liens qui m'ont été utiles, et la source de mon serveur final. J'espère que ça vous aidera si un jour vous souhaitez passer à Node.js.

    Le site officiel de Node.js
    La liste des modules disponibles
    Socket.io
    Sessions.js
    normal-template

    Source du serveur :

    var http = require('http'), 
        url = require('url'),
        fs = require('fs'),
        io = require('./socket.io'),
        sys = require('sys'),
        Sessions = require('./sessions/Sessions.js'),
        send404 = function(res){res.writeHead(404);res.write('404');res.end();},
        normal = require('./normal-template/normal-template.js'),
        session;
    
    var SessionManager = new Sessions.manager({
        lifetime: 1000
    });
    
    var server = http.createServer(function(req, res){
        session = SessionManager.lookupOrCreate(req, res);
        if (!session.data("pseudo")) session.data("pseudo","");
        var path = url.parse(req.url).pathname;
        if (/\.(js|html|swf)$/.test(path)){
            try {
                if (path=='/chat.html' || path=='/') {
                    var src = fs.readFileSync('chat.html').toString();
    		
                    var template = normal.compile(src),
                        data = {pseudo: session.data("pseudo")};
    				
                    res.writeHead(200, {'Content-Type': 'text/html'});
                    res.write(template(data));
                    res.end();
                }
                else {
                    var swf = path.substr(-4) === '.swf';
                    res.writeHead(200, {'Content-Type': swf ? 'application/x-shockwave-flash' : ('text/' + (path.substr(-3) === '.js' ? 'javascript' : 'html'))});
                    res.write(fs.readFileSync(__dirname + path, swf ? 'binary' : 'utf8'), swf ? 'binary' : 'utf8');
                    res.end();
                }
            } catch(e){ 
                send404(res); 
            }
        }
    });
    server.listen(8080, "127.0.0.1");
    		
    var buffer = [], 
        json = JSON.stringify,
        io = io.listen(server);
    		
    io.on('connection', function(client){
        client.send(json({ buffer: buffer }));
        client.broadcast(json({ announcement: client.sessionId + ' connected' }));
    
        client.on('message', function(message){
            var sep = message.indexOf(":");
            var pseudo = message.substr(0,sep);
            var mess = message.substr(sep+1);
            var msg = { message: [pseudo, mess] };
    		
            session.data("pseudo",pseudo);
    		
            buffer.push(msg);
            if (buffer.length > 15) buffer.shift();
            client.broadcast(json(msg));
        });
    
        client.on('disconnect', function(){
            client.broadcast(json({ announcement: client.sessionId + ' disconnected' }));
        });
    });
    

    • Partager sur Facebook
    • Partager sur Twitter
    Directeur technique, créateur de jeux HTML5 et fan de JavaScript | La suite de OnHack est sur les rails !
      18 octobre 2010 à 15:09:51

      Bonjour,

      Je suis également en train de prendre en main node.js car je me suis un peu agacé des problèmes de concurrence des serveur multi-thread (Java pour ma part) lorsqu'on doit gérer le temps réel.

      Si tu as rencontré des problème avec le client Flash, c'est sans doute à cause du policy-file-request, la dernière invention d'Adobe en terme de sécurité pour Flash Player (9+). Pour résoudre le problème, il faut créer un deuxième serveur qui écoute sur un port différent et qui a pour but de renvoyé le fameux policy-file lorsque le client Flash le demande.

      Cela était assez simple à mettre en place avec des serveurs Java, mais pour ma part, je bloque avec Node.js...

      Mais je ne perds pas espoir !

      En tout cas si queqlu'un à une idée, n'hésitez pas ! :)
      • Partager sur Facebook
      • Partager sur Twitter
        18 octobre 2010 à 16:20:03

        Il suffit pas de foutre un fichier à la racine pour le flash ?
        A part ça, merci bien pour ton expérience.

        Moi j'hésite toujours entre Jaxxer et Node.js...
        Parce que recoder un équivalent d'Apache avec Node.js me semble... inutile...
        • Partager sur Facebook
        • Partager sur Twitter
          19 octobre 2010 à 0:51:16

          Pour le Flash, il faut non seulement placer le fichier XML à la racine, mais aussi créer un serveur dédié pour l'envoyé au client demandeur... De mon côté ça ne marche toujours pas, mais ça ne devrait pas trop tarder !

          Jaxxer je ne connais pas.. C'est basé sur quel langages ? Mutli ou micro threading ?

          Tu n'as pas besoin de recoder un équivalent Apache ! De mon côté, j'ai un Apache qui tourne et en parallèle mes deux serveurs Node.js pour faire fonctionner mon jeu en temps réel. Cette config tourne sur mon serveur local (MAMP PRO), je n'ai pour l'instant pas essayé de la mettre en prod sur un "vrai" serveur..
          • Partager sur Facebook
          • Partager sur Twitter
            19 octobre 2010 à 12:03:19

            Jaxxer, c'est Apache + un espèce de "mod_js".
            En gros, ça te permet d'utiliser le JS à la place du PHP.

            Et ce que tu dis, ça oblige à utiliser des ports autres que le 80 :/
            • Partager sur Facebook
            • Partager sur Twitter
              19 octobre 2010 à 13:28:21

              Ok merci pour l'info !

              Pour les ports, je par du principe qu'il faut utiliser le port 80 uniquement pour les requêtes HTTP. Dans mon exemple j'utilise un serveur node.js pour gérer les connexions et le déroulement d'un jeu Flash mutlijoueurs temps réel, donc il est préférable d'utiliser d'autres ports pour faire les sockets.

              Pour être sur de ne pas être embêter par des questions de sécurité ou de ports réservé, j'ai pour habitude d'aller taper très loin dans les ports, entre 8000 et 20000 par exemple, ce qui laisse quand même le choix ! :D
              • Partager sur Facebook
              • Partager sur Twitter
                31 décembre 2010 à 18:17:51

                Tu devrais créer un tuto :)
                • Partager sur Facebook
                • Partager sur Twitter
                  31 décembre 2010 à 19:25:48

                  C'est quoi ce vieux up >_<
                  Et il écrit un tutoriel s'il a envie de le faire... pas si on lui demande.
                  Et de toutes façons, c'est pas encore prêt pour les *noobs* Node.js. Et pour les non-noobs il y a la doc qui suffit.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    17 janvier 2011 à 18:55:47

                    Salut !

                    D'une part merci d'avoir partagé ces quelques expériences, ça m'a déjà pas mal aidé.

                    J'ai mis en place un système de chat sur un site, qui tourne pas trop mal, en me basant sur ce post ainsi que d'autres ressources à droite à gauche. Le seul truc qui me bloque c'est l'histoire des sessions... je ne suis pas un expert javascript et j'ai pas mal de difficultés à trouver des ressources sur le sujet. Tu en aurais sous le coude à m'indiquer ?

                    J'ai jeté un oeil à la source sur laquelle tu t'es basé et que tu dis avoir adapté à tes besoins, mais honnêtement, j'y entrave pas grand chose >_<'

                    Merci !

                    OSteEL

                    EDIT du 20/01/11

                    Bon j'ai trouvé 2-3 trucs depuis, je les poste au cas où quelqu'un d'autre serait intéressé.

                    Ici un post traitant pile-poil des sessions avec node.js : http://stackoverflow.com/questions/373 [...] ons-in-nodejs

                    Et ici un autre avec davantage de ressources sur le sujet : http://stackoverflow.com/questions/460 [...] ner-tutorials
                    • Partager sur Facebook
                    • Partager sur Twitter

                    Node.js : Mes expérimentations

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown