JeuWeb - Crée ton jeu par navigateur
[Node.js] Utilisation de Socket.IO - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [Node.js] Utilisation de Socket.IO (/showthread.php?tid=5897)

Pages : 1 2 3 4 5


RE: [Node.js] Utilisation de Socket.IO - quentin01 - 31-12-2011

Ton code ne va pas pour la création du cookie, ni pour la récupération de l'id de session. Il ne faut pas oublier que le serveur sera appellé par plusieurs utilisateurs et que donc la fonction de callback que tu donnes à createServer sera exécuté par plusieurs utilisateurs différents. C'est pour cela que la méthode la plus simple est que le client lui même envoit l'id de session au serveur. Pour l'histoire de la création du cookie, c'est une bonne idée mais il faudra le rajouter aux en-tete HTTP de l'objet req qui récupère le contenu de ton PHP.

Ba dans ce cas là il faut faire un setTimeout côté serveur pour relancer l'evenement. Mais ton système est bancale si c'est ce que tu cherches à faire ! Les sockets ce n'est pas le même raisonnement que l'Ajax. Pour un tel système il faudrait plutôt qu'un client envoit au serveur qu'il a invité un autre utilisateur dans un chat privé, que celui dise justement à cette utilisateur qu'il a été invité dans un chat privé en lui envoyant quelque chose, et que côté client tu fasses l'affichage. C'est la solution qui devrait normalement être utilisé. Pareil pour le chat, un client envoit un message, le serveur le renvoit à tous les usagers. Un client se connecte au chat, le serveur lui renvoit l'historique des messages. Ensuite le Javascript côté client fait l'affichage en fonction des données reçus. Il ne faut plus voir les choses de la même façon qu'avec Ajax ! D'ailleurs, je ne l'ai pas dit avant mais les websockets c'est normalement fait pour passer des données, pas du code source.

Donc après pour tes déplacements c'est la même chose, soit le serveur dit à chaque client où se trouvent chaque personnage a tant d'intervalle, ou alors dès qu'un utilisateur bouge le serveur en est informé et renvoit cette socket à tous les autres clients.

Edit : Pour te montrer l'absurdité de la chose, c'est un peu comme si un serveur de MMORPG passait l'image que doit afficher le client. Dans certains cas ça se comprend, mais pour un tel système c'est pas forcément le mieux.


RE: [Node.js] Utilisation de Socket.IO - Maks - 31-12-2011

Ouais tu as raison je m'en rends compte je raisonne comme si c'était Ajax :/

Faut que je lache PHP/MySQL et que je fasse tout par "channel" ^^

Ce qui m'embête c'est pour garder une "trace" des messages, déplacements ect


RE: [Node.js] Utilisation de Socket.IO - quentin01 - 31-12-2011

Justement Node.JS est plus fait pour ça, les "traces" des actions ou les données des joueurs peuvent facilement être stocké en BDD vu que Node.JS a des modules pour ça. Tu peux tout aussi bien stocker des données dans des fichiers JSON aussi, vu que le javascript et le PHP supporte très bien en natif ce langage de structuration des données. En tous cas si t'as encore besoin d'aide demande Wink


RE: [Node.js] Utilisation de Socket.IO - Maks - 31-12-2011

Très bien merci pour ton aide Quentin, je reviendrai vers toi prochainement lorsque j'aurai intégré tout ça Smile


RE: [Node.js] Utilisation de Socket.IO - Maks - 02-01-2012

Malgré mon relatif état de fraicheur, je me suis penché sur la question aujourd'hui ^^
Il en ressort que je m'en suis bien sorti. Passons au code tout de suite :

Serveur (server.js)

Code :
var http = require('http');

var app = http.createServer(function(req, res) {});
app.listen(8080);

var io = require('socket.io');
var io = io.listen(app);

var mysql = require('mysql');
var db = 'bdd';

var client = mysql.createClient({
    user : 'root',
    password : ''
});

client.query('USE '+db);

// maintenance
var trois_jours = 60*60*24*3;
client.query('DELETE FROM chat WHERE UNIX_TIMESTAMP() - UNIX_TIMESTAMP(date) > '+ trois_jours);

var sept_jours = 60*60*24*7;
client.query('DELETE FROM evenement WHERE UNIX_TIMESTAMP() - UNIX_TIMESTAMP(date) > '+ sept_jours);

function newFormatDateSQL() {
    var date = new Date();
    var year = date.getFullYear();
    var month = parseInt(date.getMonth())+1;
    if(month < 10) month = '0' + month;
    var day = date.getDate();
    if(day < 10) day = '0' + day;
    var hours = date.getHours();
    if(hours < 10) hours = '0' + hours;
    var minutes = date.getMinutes();
    if(minutes < 10) minutes = '0' + minutes;
    var seconds = date.getSeconds();
    if (seconds < 10) seconds = '0' + seconds;
    var formatDate = year + '-' + month + '-' + day + ' ' + hours + '-' + minutes + '-' + seconds;
    return formatDate;
}

var noFlood = true;

io.sockets.on('connection', function (socket) {

    socket.on('init', function (map, pseudo) {

        var html = '';
        client.query(
            "SELECT pseudo, message, DATE_FORMAT(date, '%H:%i') AS date2 FROM chat WHERE nomMap = '"+ map +"' ORDER by date DESC LIMIT 30",
            function selectCb(err, results, fields) {
                if (err) {
                  throw err;
                }
                for (var i = 0, l = results.length; i < l; ++i) {
                    var r = results[i];
                    if(r['pseudo'] == '__root') html += "<span style='color:#888'><b>" + r['message'] + "</b></span><br />";
                    else html += "<b>" + r['pseudo'] + "</b> (" + r['date2'] + ") : " + r['message'] + "<br />";
                }
                socket.emit('showMsgsChat', html);
            }
        );
        
        var html2 = '';
        client.query(
            "SELECT evenement, DATE_FORMAT(date, '%d %b %H:%i') AS date2 FROM evenement WHERE pseudo = '"+ pseudo +"' ORDER by date DESC LIMIT 30",
            function selectCb(err, results, fields) {
                if (err) {
                  throw err;
                }
                for (var i = 0, l = results.length; i < l; ++i) {
                    var r = results[i];
                    html2 += "<b>" + r['date2'] + "</b> : " + r['evenement'] + "<br />";
                }
                socket.emit('showEvents', html2);
            }
        );
    });

    socket.on('newMsgChat', function (message, pseudo, map) {

        if(message.length == 0) {
            var errorMsg = "<span style='color:#888'><b>< Veuillez entrer un message ></b></span><br />";
            socket.emit('errorChat', errorMsg);
        }
        else if(message.length > 30) {
            var errorMsg = "<span style='color:#888'><b>< Votre message est trop long (30 caractères max) ></b></span><br />";
            socket.emit('errorChat', errorMsg);
        }
        else if(noFlood == false) {
            var errorMsg = "<span style='color:#888'><b>< Vous devez atteindre une minute avant de pouvoir reposter ></b></span><br />";
            socket.emit('errorChat', errorMsg);
        }
        else {

            client.query(
                'INSERT INTO chat(nomMap, pseudo, message, date) VALUES (?, ?, ?, ?)',
                [map, pseudo, message, newFormatDateSQL()]
            );

            // contrôle du flood
            noFlood = false;
            setTimeout(function() { noFlood = true; }, 60000);
            
            var html = '';
            client.query(
                "SELECT pseudo, message, DATE_FORMAT(date, '%H:%i') AS date2 FROM chat WHERE nomMap = '"+ map +"' ORDER by date DESC LIMIT 30",
                function selectCb(err, results, fields) {
                    if (err) {
                      throw err;
                    }
                    for (var i = 0, l = results.length; i < l; ++i) {
                        var r = results[i];
                        if(r['pseudo'] == '__root') html += "<span style='color:#888'><b>" + r['message'] + "</b></span><br />";
                        else html += "<b>" + r['pseudo'] + "</b> (" + r['date2'] + ") : " + r['message'] + "<br />";
                    }
                    socket.emit('showMsgsChat', html);
                    socket.broadcast.emit('showMsgsChat', html);
                }
            );
        }
    });
});

//client.end();

Client : (rpg.js, là où j'ai mon onload)

Code :
    var socket = io.connect('http://127.0.0.1:8080');

    if(map.horde == 0) var nomMap = map.nom;
    else var nomMap = 'horde:'+map.idHorde+':'+map.nom;
    socket.emit('init', nomMap, joueur.pseudo);

    socket.on('showMsgsChat', function (data) {
        document.getElementById('divSupportChat').innerHTML = data;
    });
    socket.on('errorChat', function (data) {
        document.getElementById('divSupportChat').innerHTML = data + document.getElementById('divSupportChat').innerHTML;
    });
    socket.on('showEvents', function (data) {
        document.getElementById('divSupportEvent').innerHTML = data;
    });

Quelques explications quand même Smile
J'ai du tout réécrire mon PHP en JS (dingue quand même de faire du SQL avec JS ^^).
- Inconvénients : Perte de temps, PHP va me manquer :'(, manque de fonctions (obligé réécrire celle pour la date)
- Avantages : Evenementiel possible, rapidité
Pour les histoires de session, je suis bête j'avais oublié que pseudo et map je l'ai ai en variable JS. Du coup j'attends que le client envoie "init" avec pseudo et nomMap pour déclencher le reste...

Problèmes rencontrés :
- Si je laisse client.end(); il ferme la connection MySQL et après impossible de rajouter de nouveaux messages.

Inconvénients :
- Celui qui se rend sur 127.0.0.1/server.js a accès aux identifiants de la bdd.. -.-
=> Comment faire pour protéger ? Générer deux MD5, un pour le dossier distant, l'autre pour le nom du fichier .js mais pas encore suffisant surement. Mettre un .htacess et .htpasswd ? Risque pas de faire planter Node qui n'arriverait pas à acceder à server.js avec la commande node server.js ?

Et le plus gros inconvénient : Le code est déguelasse là. Y'a rien d'organiser Sad
Si je fous tout sur server.js ça va vite ressembler à rien. Express peut m'aider ?



RE: [Node.js] Utilisation de Socket.IO - quentin01 - 02-01-2012

Pourquoi mettre le client.end() ? Le Javascript est Asynchrone c'est pour cela qu'il est executé avant même qu'une connexion se fasse au serveur. Il faut soit l'enlever, soit le rajouter à la fermeture du serveur. ( Donc avec un événement, mais je ne sais pas lequel ).

Concernant l'accès à server.js. L'utilisation d'un .htaccess avec un "deny from all" ( juste pour le fichier server.js ) fera que personne ne peut accèder à ton fichier. Sauf que tu as du oublier un truc, c'est Apache qui gère les .htaccess ! Et donc Node.JS ne passe pas par Apache pour récupérer server.js, il ne sera donc pas bloqué.

Aussi pour tes codes, il y a différents moyens de les simplifier et de les rendre plus lisible :
- Utiliser la POO en Javascript, surtout que Node.JS fournit une méthode qui permet l'héritage facilement, ce qui n'est pas possible en JS Natif.
- Dispatcher ton code en plusieurs fichiers ? Pour cela il suffit d'utiliser require et de te renseigner sur la manière de l'utiliser. ( Tout est expliqué dans la doc' ).


RE: [Node.js] Utilisation de Socket.IO - niahoo - 02-01-2012

l'héritage en JS est tout à fait possible, il utilise les prototypes ! Sinon, question qui va peut-être paraître bête, mais pourquoi est-ce que ton fichier server.js se trouve dans le 'document root' du serveur ?


RE: [Node.js] Utilisation de Socket.IO - quentin01 - 02-01-2012

L'héritage est possible mais pas de manière native. Donc pas avec un mot clé. Après oui il est possible d'utiliser astucieusement le JS pour faire de l'héritage, mais c'est pas la même chose qu'un solution native ou juste l'appel à une méthode.


RE: [Node.js] Utilisation de Socket.IO - niahoo - 02-01-2012

Non mais c'est pas « astucieusement », c'est juste comme ça qu'il est prévu de faire en javascript pour l'héritage : en donnant un prototype.

niahoo — désolé pour le HS


RE: [Node.js] Utilisation de Socket.IO - Maks - 02-01-2012

(02-01-2012, 03:02 PM)quentin01 a écrit : Pourquoi mettre le client.end() ? Le Javascript est Asynchrone c'est pour cela qu'il est executé avant même qu'une connexion se fasse au serveur. Il faut soit l'enlever, soit le rajouter à la fermeture du serveur. ( Donc avec un événement, mais je ne sais pas lequel ).

Concernant l'accès à server.js. L'utilisation d'un .htaccess avec un "deny from all" ( juste pour le fichier server.js ) fera que personne ne peut accèder à ton fichier. Sauf que tu as du oublier un truc, c'est Apache qui gère les .htaccess ! Et donc Node.JS ne passe pas par Apache pour récupérer server.js, il ne sera donc pas bloqué.

Aussi pour tes codes, il y a différents moyens de les simplifier et de les rendre plus lisible :
- Utiliser la POO en Javascript, surtout que Node.JS fournit une méthode qui permet l'héritage facilement, ce qui n'est pas possible en JS Natif.
- Dispatcher ton code en plusieurs fichiers ? Pour cela il suffit d'utiliser require et de te renseigner sur la manière de l'utiliser. ( Tout est expliqué dans la doc' ).

- Ce qui serait bien c'est d'avoir un évènement déconnexion pour que je puisse fermer la connexion à MySQL, que je mette à jour la table joueurs et que je retire le joueur qui vient de se déconnecter du Array des joueurs ^^

- Ouep pour le .htaccess j'ai réussi en effet Smile

- J'avais pas encore croisé de code aussi complet, mais si on peut utiliser prototype dans Node.JS c'est tout bon alors me reste qu'à faire comme d'habitude Smile
En plusieurs fichiers ça serait le top ouais, avec require ça doit le faire en effet.

Pour l'héritage dans Node.JS me semble avoir croisé un code avec un extends.
Sinon de mémoire c'est myClass.prototype = new Object(); ce qui reste assez spécial d'ailleurs.

Sinon j'ai un autre problème qui se pose : Sur ma map, côté client, j'ai un évènement qui fait bouger mes bots avec un setInterval(); selon un random.
Seulement comme c'est coté client personne ne verra les bots bouger de la même façon.
Comment je peux faire pour uniformiser ça ? Mettre un évènement côté serveur plutôt ?