node.JS
&
Socket.io

par Robin Duval

Socket.io

  • Socket.io
    • une bibliothèque JavaScript (événementiel)
    • pour les applications web en temps réel
    • communication bidirectionnelle : client <=> serveur
  • Il comporte deux parties:
    • une bibliothèque côté client (navigateur), 
    • une bibliothèque côté serveur pour Node.js
      • Les APIs sont quasiment identiques

Socket.io

  • Socket.IO utilise principalement le protocole WebSocket

    • avec un système de polling comme option de repli

    • tout en offrant la même interface

  • Socket.IO peut être utilisé

    • comme un simple wrapper WebSocket,

    • broadcasting vers de multiples clients (socket)

    • stockage des données associées à chaque client

    • et gestion des entrés / sorties asynchrones.

Node.JS

  • Node.js 
    • est une plateforme logicielle libre et événementielle 
    • est en JavaScript 
    • s'oriente vers les applications réseau (+monter en charge).
    • utilise la machine virtuelle V8 
    • implémente sous licence MIT les spécifications CommonJS.

Node.JS

  • Node.js
    • contient une bibliothèque de serveur HTTP intégrée
      • on fait tourner un serveur web
        • sans Apache ou Lighttpd
      • on contrôle la façon dont le serveur web fonctionne en live
    • est utilisé par
      • Groupon, SAP, LinkedIn, Microsoft,
      • Yahoo!, Walmart, Rakuten et PayPal.

Travaux PRATIQUEs

  • Cahier des charges
    • avoir un formulaire avec +100 champs
    • diffuser
      • la mise à jour du formulaire
      • l'identifications des personnes (dé)connectées
      • l'historique des modifications

TP Côté Client : VIOU

Création de la page htm(euh)l

<!DOCTYPE html>
<html lang="fr">
<body style="width: 100%">

<form style="float:left;width: 55%" action="" id="healthForm"></form>

<div style="margin-left: 55%" id="history">
    <form action="" id="loginForm">
        <input type="text" name="username" id="username" placeholder="Ton nom" />
    </form>

    Liste des utilisateurs connectés
    <ul id="users"></ul>

    Liste des utilisateurs connectés
    <ul id="activities"></ul>

</div>

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="js/client/generateForm.js"></script>
<script type="text/javascript" src="http://192.168.3.240:1337/socket.io/socket.io.js"></script>
<script type="text/javascript" src="js/client/rules.js"></script>

</body>
</html>

TP Côté Client : VIOU

Génération du formulaire (generateForm.js)

(function ($){

    for (i = 1; i <= 100; i++) {
        $('#healthForm').append('<input style="border-color:yellow;" value="'+ Math.trunc(Math.random()*1000000) +'" type="text" pfd="src int" class="src" id="si' + i + '" />');
        $('#healthForm').append('<input style="border-color:grey;"   type="text" pfd="dst int" id="da' + i + '" class="text" />');
        $('#healthForm').append('<input style="border-color:grey;"   type="text" pfd="dst int" id="db' + i + '" class="text" />');
        $('#healthForm').append('<input style="border-color:grey;"   type="text" pfd="dst int" id="dc' + i + '" class="text" /><br />');

        $('#healthForm').append('<input style="border-color:blue;"  value="'+ Math.random().toString(36).substring(7) +'"  type="text" pfd="src txt" class="src" id="st' + i + '"/>');
        $('#healthForm').append('<input style="border-color:grey;"   type="text" pfd="dst txt" id="da' + i + '" class="text" />');
        $('#healthForm').append('<input style="border-color:grey;"   type="text" pfd="dst txt" id="db' + i + '" class="text" />');
        $('#healthForm').append('<input style="border-color:grey;"   type="text" pfd="dst txt" id="dc' + i + '" class="text" /><br /><br />');
    }
})(jQuery);

TP : Gestion des Uzeurs

Côté Client

(function ($){
    //NOTRE CHAUSSETTE VA SE CONNECTER SUR NOTRE SERVEUR HTTP (NODEJS)
    var socket = io.connect('http://192.168.3.240:1337');
    var user = "";

    $('#loginForm').submit(function (event){
        event.preventDefault();

        user = $('#username').val();
        // NOTRE SOCKET EMET VERS LE SERVEUR HTTP SUR LE CANAL/EVENEMENT LOGIN
        socket.emit('login', {
            username : $('#username').val()
        });
        $('#loginForm').hide();
    });


    // NOTRE SOCKET ATTENDS QUE QQ1 LUI DISE QUOI FAIRE SUR L'EVENEMENT NEWUSER
    socket.on('newuser', function(user){
        $('#users').append('<li id="'+user.id+'">' + user.id + '</li>');
    });

    // NOTRE SOCKET ATTENDS QUE QQ1 LUI DISE QUOI FAIRE SUR L'EVENEMENT DISUSER
    socket.on('disuser', function(user){
        $('#'+user.id).remove();
    });

})(jQuery);

TP : Gestion des Uzeurs

Côté Serveur

// VARIABLE GLOBALE
var http = require('http');
var io = require('socket.io');

httpServer = http.createServer(function(req, res){
    res.end("check this out");
});

//Creation du serveur http avec nodeJs, il écoute sur le 1337 
httpServer.listen(1337);

// Notre socket est connecté au serveur http
var io = require('socket.io').listen(httpServer);
var users = {};

// ON SE BRANCHE SUR L'EVENEMENT LIE A UNE CONNEXION / UN SOCKET
// VARIABLE SPECIFIQUE A UN SOCKET / UTILISATEUR
io.sockets.on('connection', function(socket){
    var me = false;
    for (var k in users){
        socket.emit('newuser', users[k]);
    }

    socket.on('login', function(user){
        me = user;
        me.id = user.username;
        users[me.id] = me;

        //ENVOYER UN EVENEMENT DU SERVEUR --> vers le client celle qui est connecté
        //socket.emit('newuser');

        //ENVOYER UN EVENEMENT DU SERVEUR --> vers les clients qui sont connectés SAUF le user COURANT
        //socket.broadcast.emit('newuser');

        //ENVOYER UN EVENEMENT DU SERVEUR --> vers les clients qui sont connectés
        io.sockets.emit('newuser', me);
    });

    socket.on('disconnect', function(){
        if (!me){
            return false;
        }
        delete users[me.id];
        io.sockets.emit('disuser', me);
    });
});

TP : Gestion dU FORMUL-R

Côté Client

(function ($){
    // On récupère l'info du formulaire
    $('.src').focusout(function (event){
        event.preventDefault();
        socket.emit('updateValue', {
            id        : $(this).attr('id'),
            typeNode  : $(this).attr('pfd').split(" ")[0],
            typeValue : $(this).attr('pfd').split(" ")[1],
            value     : $(this).val(),
            user      : user
        });
    });

    // ON AFFICHE L'INFORMATION SUR UN LOG
    function log(field) {
        $('#activities').prepend('<li id="'+field.id+'">' +
            'Le champ #' + field.id +
            ' a pris la valeur ' + field.value +
            '. Le type est ' + field.typeValue +
            ' par ' + field.user +
            '</li>');
    }

    // ON RECUPERE L'INFORMATION SUR L'EVENEMENT ACTIVITY
    socket.on('activity', function(activity){
        var color = "red";
        if (activity.isValid) {
            color = "green";
        }

        $('#'+activity.id).val(activity.value);
        $('#'+activity.id).css("border-color", color);
        log(activity);

    });

    // ON AFFICHE OU NON LE CHAMPS
    socket.on('hide', function(id){
        $('#activities').prepend('<li style="color:red" id="'+id+'">' +
        'Le champ #' + id +
        ' a été caché </li>');

        $('#'+id).hide();
    });

    socket.on('show', function(id){
        $('#activities').prepend('<li style="color:red" id="'+id+'">' +
        'Le champ #' + id +
        ' a été montré </li>');

        $('#'+id).show();
    });

})(jQuery);

TP : Gestion dU FORMUL-R

Côté Serveur

function replaceTag(tag) {
    var tagsToReplace = {
        '&': '&',
        '<': '<',
        '>': '>'
    };
    return tagsToReplace[tag] || tag;
}

function is_int(value){
    if((parseFloat(value) == parseInt(value)) && !isNaN(value)){
        return true;
    } else {
        return false;
    }
}

function fixTheForm(field){
    var rules =
    {
        "si1":
        {
            src: "si1",
            dest: "da2 db2 dc2",
            type: "int",
            action: "display"
        },
        "st2":
        {
            src: "st2",
            dest: "da2 db2 dc2",
            type: "txt",
            action: "hide"
        },
        "si3":
        {
            src: "si3",
            dest: "da3 db3 dc3",
            type: "int",
            action: "display"
        },
    };

    if (typeof rules[field.id] != 'undefined'){
        rule = rules[field.id];
        field.existRule = true;
        field.isValid = true;

        if ("int" === rule.type){
            field.isValid = is_int(field.value);
        }

        if ("display" === rule.action){
            field.displays = rule.dest.split(" ");
        }

        if ("hide" === rule["action"]){
            field.hides = rule.dest.split(" ");
        }
    }

    return field;
}
   


   
     
    // A LA CONNEXION - A L'INTERIEUR
    socket.on('updateValue', function(field){
        newfield = field;
        newfield.existRule = false;
        newfield.displays = {};
        newfield.hides = {};
        newfield.isValid = true;
        newfield.value = newfield.value.replace(/[&<>]/g, replaceTag);

        fixTheForm(newfield);
        for (var k in newfield.hides){
            io.sockets.emit('hide', newfield.hides[k]);
        }

        for (var k in newfield.displays){
            io.sockets.emit('show', newfield.displays[k]);
        }

        io.sockets.emit('activity', newfield);
    });

VERS L'INFINI ET au delà ! 1/3

  • ExpressJS : framework web minimalist pour node.js
    • Pleins d'outils
      • pour créer rapidement une API 
      • pour créer des applications web et mobiles
    • couche fine pour couvrir les besoins fondamentaux
      • gestion du routing 
      • générateur d'un squelette 
      • gestion des erreurs
      • possibilité d'utiliser un moteur de template ...
      • gestion de la base de données

VERS L'INFINI ET AU DELÀ ! 2/3

  • Loopback : framework pour créer une API + connexion bdd
    • Créez rapidement une API REST de bout en bout.
    • Extension pour gérer :
      • les pushs,
      • gestion de fichiers,
      • et la géolocalisation...
    • Permet de définir un model de données :
      • hasMany, belongsTo, hasAndBelongsToMany
    • Automatically generates corresponding relational REST endpoints
    • Utilisez StrongLoop Arc pour modifier, déployer et contrôler des applications fait avec Loopback...

VERS L'INFINI ET AU DELÀ ! 3/3

  • Apache :
    • Cassandra : table avec index et valeur, stockage clé+valeur en colonne 
    • CouchBD : document JSON
  • Google
    • LevelDB : stockage clé (ordonné)-valeur de chaîne de caractères
  • Neo4j : stockage de graph très performant (payant)
  • Redis : gestion de cache, stockage clé+valeur

C'est

terminé !

SocketIO+NodeJS

By Robin Duval

SocketIO+NodeJS

Débuter avec SocketIO+NodeJS

  • 405