Partage
  • Partager sur Facebook
  • Partager sur Twitter

[socket.io]Modulariser io.on('connection', ...)

    15 octobre 2021 à 11:56:03

    Bien le bonjour.

    Voici mon problème, je bosse sur un projet d'application express proposant à la fois un serveur HTTP "standard" et un serveur socket.io. Les utilisateurs connectés à leur compte utilisateur se voient ainsi attribuer une connexion socket.io.
    La connexion socket.io a pour but de permettre un affichage en temps réel des utilisateurs connectés, et également de gérer les échanges d'informations entre les utilisateurs.
    Et donc avec mes maigres connaissances et aptitudes, je me retrouve avec un fichier app.js de plus de 300 lignes, dont pas loin de 180 lignes pour la gestion des sockets, à savoir ce qui est regroupé dans la seule instruction io.on('connection', (socket) => {...}).

    J'aimerais donc "modulariser" cette fonction dans un fichier dédié, mais j'avoue ne pas bien savoir comment procéder ^^

    A toute fins utiles je joint mon fichier app.js :

    const express = require('express');
    const app = express();
    const util = require('util');
    const createError = require('http-errors');
    const path = require('path');
    const cookieParser = require('cookie-parser');
    const logger = require('morgan');
    const session = require('express-session');
    const http = require('http');
    const cors = require('cors');
    const MongoStore = require('connect-mongo');
    const assert = require('assert');
    const MongoClient = require('mongodb').MongoClient;
    const mongoose = require("mongoose");
    
    //gestion des connexion bdd
    const dbclient = new MongoClient('mongodb://localhost:27017/mydb', { useUnifiedTopology: true });
    let _dbConnexion = null;
    dbclient.connect(function(err, dbConnexion){
        console.log("Connected successfully to db from app.js");
        assert.equal(null, err);
        _dbConnexion = dbConnexion;
    })
    app.use(function(req, res, next) {
        res.locals.dbConnexion = _dbConnexion;
        next();
    });
    
    mongoose.connect('mongodb://localhost:27017/mydb', {useNewUrlParser: true, useUnifiedTopology: true});
    let _mongooseDBconnexion = null;
    var mongooseDBconnexion = mongoose.connection;
    mongooseDBconnexion.on('error', console.error.bind(console, 'mongoose connection error : '));
    mongooseDBconnexion.once('open', function() {
        console.log('connected to mongooseDB from app.js');
        _mongooseDBconnexion = mongooseDBconnexion;
    });
    app.use(function(req, res, next) {
        res.locals.mongooseDBconnexion = _mongooseDBconnexion;
        next();
    });
    
    //modules persos
    const sessionsManage = require('./handmade_modules/sessionsManage.js');
    const morpionManager = require('./handmade_modules/morpion-server.js');
    
    //Création des sessions
    const httpSession = session({
        store: MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/mydb' }),
        secret: 'keepItSecret',
        resave: false,
        saveUninitialized: false,
        unset: 'destroy',
        cookie: { secure: false, maxAge: 600000 }
    });
    app.use(httpSession);
    
    //Création serveur socket.io
    const wsServer = http.createServer(app);
    const {Server} = require('socket.io');
    const io = new Server(wsServer, {
        cors: {
            origin: true,  //ports 8080 et 3000? tous les ports du localhost?
            methods: ["GET", "POST"],
            allowedHeaders: 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization',
            credentials: true
        }
    });
    wsServer.listen(8080, () => {
        console.log('serveur webSocket créé sur port 8080');
    });
    
    
    //création des routes
    const indexRouter = require('./routes/index');
    const usersRouter = require('./routes/users');
    const logRouter = require('./routes/log');
    const morpionRouter = require('./routes/morpion');
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    
    //tiré du cours openclassrooms sur node, express, mongo
    app.use((req, res, next) => {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
        next();
    });
    
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(express.static(path.join(__dirname, 'public')));
    
    
    //gestion des connections socket.io
    io.on('connection', (socket) => {
        console.log('a user connected');
        //setTimeout(function(){socket.emit('message', 'Le serveur vous dis bonjour!');}, 500);
        //setTimeout(function(){socket.emit('message', 'Le serveur vous demande si vous allez bien.');}, 5000);
        socket.on('start-session', (data) => {
            if(data.socketID === null)
            {
                socket.username = data.username;
                socket.join(data.username);
                if(socket.rooms.has(data.username))
                {
                    socket.emit("set-session-aknowledgement", { socketID: data.username});
                    sessionsManage.findSessions(_dbConnexion).then((value) => {
                        socket.broadcast.emit('newConnection', {newOne: socket.username, userList: value});
                    });
                }
            }
            else
            {
                socket.username = data.username;
                socket.join(data.username);
                if(socket.rooms.has(data.username))
                {
                    sessionsManage.findSessions(_dbConnexion).then((value) => {
                        socket.emit("set-session-aknowledgement", { socketID: data.socketID, userList: value});
                    });
                }
                if(data.inGame == false){ // L'utilisateur vient-il de quitter un jeu en cours ?
                    morpionManager.games.forEach((value, key, map) => {
                        if(value.player1 == socket.username){
                            console.log(socket.username + ' a abandonné un jeu.');
                            io.to(value.player2).emit('gameLeft', {user: socket.username});
                        }
                        if(value.player2 == socket.username){
                            console.log(socket.username + ' a abandonné un jeu.');
                            io.to(value.player1).emit('gameLeft', {user: socket.username});
                        }
                    })
                }
            }
        });
        
        socket.on("disconnect", (reason) => {
            if(socket.username)
                console.log(socket.username + ' disconnected : ' + reason);
            setTimeout(function(){sessionsManage.findSessions(_dbConnexion).then((value) => {
                
                //L'utilisateur a-t-il quitté une partie en cours
                function checkGames(value, key, map){
                    if(value.player1 === socket.username){
                        console.log(socket.username + ' a abandonné un jeu.');
                        io.to(value.player2).emit('gameLeft', {user: socket.username});
                    }
                    if(value.player2 === socket.username){
                        console.log(socket.username + ' a abandonné un jeu.');
                        io.to(value.player1).emit('gameLeft', {user: socket.username});
                    }
                }
                //Déconnection
                if(value.users.indexOf(socket.username)<0)
                {
                    io.emit('userLeft', {goneOne: socket.username, userList: value});
                    morpionManager.games.forEach(checkGames);
                }
                //Fermeture de fenêtre sans déconnection
                else if(!io.to(socket.username).adapter.rooms.has(socket.username)){
                    console.log(socket.username + ' a quitté le site ( sans se déconnecter)');
                    morpionManager.games.forEach(checkGames);
                    ////
                    // TODO enlever le nom de l'utilisateur de la userList
                    ////
                    //io.emit('userLeft', {goneOne: socket.username, userList: value});
                }
            })}, 2000);
        });
        socket.on("invite", (data) => {
            io.to(data.guest).emit('message', data.host + " vous a invité!");
            
            ////
            //TODO : mieux gérer l'asynchrone, émettre les messages une fois que la BDD est mise à jour
            ////
            sessionsManage.findUserSessionId(_dbConnexion, data.host).then((sessionId) => {
                sessionsManage.addHostInvite(_dbConnexion, sessionId, data.guest);
            });
            sessionsManage.findUserSessionId(_dbConnexion, data.guest).then((sessionId) => {
                sessionsManage.addGuestInvite(_dbConnexion, sessionId, data.host);
            });
            
            setTimeout(function(){
                sessionsManage.findSessions(_dbConnexion).then((value) => {
                    //socket.broadcast.emit('newConnection', {newOne: socket.username, userList: value});
                    io.to(data.host).emit('updateUserList', {userList: value});
                    io.to(data.guest).emit('updateUserList', {userList: value});
            })}, 2000);
            ////
            // Fin TODO
            ////
            
        });
        socket.on("openGame", (data) => {
            console.log("Commencer une partie\nHôte : " + data.host + "\nInvité : " + data.guest);
            // intégrer l'invité dans la room de l'hôte
            for(let client of io.sockets.sockets){
                if(client[1].username == data.guest)
                    client[1].join(data.host);
            }
            
            for(client of io.sockets.sockets){
                if(client[1].username == data.host)
                    console.log('room "' + data.host + '" : ' + util.inspect(client[1].rooms));
            }
            // Lancer une partie entre les deux joueurs
            //redirige les joueurs
            io.to(data.host).emit('gameStarted', {guest: data.guest});
            io.to(data.guest).emit('gameStarted', {host: data.host});
            //créé l'instance MorpionGame
            morpionManager.games.set(data.host, new morpionManager.MorpionGame(data.host, data.guest));
            // supprimer les hostInvites et guestInvites
            sessionsManage.findUserSessionId(_dbConnexion, data.host).then((sessionId) => {
                sessionsManage.removeHostInvite(_dbConnexion, sessionId, data.guest);
            });
            sessionsManage.findUserSessionId(_dbConnexion, data.guest).then((sessionId) => {
                sessionsManage.removeGuestInvite(_dbConnexion, sessionId, data.host);
            });
        });
        //page de jeu chargée par un joueur
        socket.on('gameLoaded', (data) => {
            let gameHost;    
            if(morpionManager.games.has(data)){
                console.log(morpionManager.games.get(data));
                gameHost = data;
            }
            else{
                console.log('Pas de jeu au nom de ' + data);
                morpionManager.games.forEach(function(value, key, map){
                    if(value.player2 === data){
                        socket.join(value.player1);
                        io.to(value.player1).emit("message", 'Message émis par room ' + value.player1);
                        gameHost = value.player1;
                    }
                });
            }
            io.to(data).emit('setHost', gameHost);
        });
        socket.on('cellPlayed', (data) => { // jouer le coup
            io.to(data.gameHost).emit('message', data.player + ' joue en ' + data.cellPlayed);
            let returnOfPlay = morpionManager.games.get(data.gameHost).play(data.player, data.cellPlayed);
            if(returnOfPlay.error)
                console.log('returnOfPlay Error :' + returnOfPlay.error);
            else{
                console.log('Réponse : ' + returnOfPlay.message);
                io.to(data.gameHost).emit('drawCell', {token: returnOfPlay.token, cell: returnOfPlay.cellToDraw, turn: morpionManager.games.get(data.gameHost).turn});
                if(returnOfPlay.result){
                    console.log('result.draw : ' + returnOfPlay.result.draw + '\nresult.gagnant : ' + returnOfPlay.result.gagnant + '\nCases : ' + returnOfPlay.result.cells);
                    io.to(data.gameHost).emit('gameResult', returnOfPlay.result);
                }
            }
        });
        socket.on('gameReload', (data) => {
            console.log('reload ' + data.host + " from : " + data.from);
            let otherPlayer
            let askingPlayer
            if(data.host == data.from){
                otherPlayer = 'player2';
                askingPlayer = 'player1';
            }
            else{
                otherPlayer = 'player1';
                askingPlayer = 'player2';
            }
            if(morpionManager.games.get(data.host).reload.get(otherPlayer)){ //relancer le jeu
                let reloadGuest = morpionManager.games.get(data.host).player2;
                morpionManager.games.set(data.host, new morpionManager.MorpionGame(data.host, reloadGuest));
                io.to(data.host).emit('reloadGame', {host: data.host, guest: morpionManager.games.get(data.host).player2});
            }
            else{ //enregistrer la demande de reload et prévenir les joueurs
                morpionManager.games.get(data.host).reload.set(askingPlayer, true);
                io.to(data.host).emit('reloadAsked', {host: data.host, by: data.from});
            }
        })
        
        socket.on('gameLeave', (data) => {
            console.log('game left ! ' + data.user + ' quitte la partie de ' + data.gameHost);
        })
    });
    
    
    //Gestion des routes
    app.use('/', indexRouter);
    app.use('/users', usersRouter);
    app.post('/log', logRouter);
    app.use('/log', logRouter);
    app.use('/morpion', morpionRouter);
    
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
      next(createError(404));
    });
    
    // error handler
    app.use(function(err, req, res, next) {
      // set locals, only providing error in development
      res.locals.message = err.message;
      res.locals.error = req.app.get('env') === 'development' ? err : {};
    
      // render the error page
      res.status(err.status || 500);
      res.render('error');
    });
    
    module.exports = app;

    Alors bon, je précise que certaines fonctions définies dans io.on('connection', (socket) => {...}) doivent pouvoir accéder aux variables de l'espace global de app.js, et c'est là dessus que je me sens moins à l'aise.

    D'avance merci de votre attention.

    • Partager sur Facebook
    • Partager sur Twitter

    [socket.io]Modulariser io.on('connection', ...)

    × 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