Search code examples
node.jsvue.jssocket.io

why is only one of my client side sockets receiving the emit from the server using socket.io?


So i got my server setup with express and nodejs as follows

here is a mini project which encapsulates better what i want to achieve: https://file.io/2OFIswnufLFO

I think the main problem is i dont think my socket class is setup correctly and i am unable to find any good examples that i can understand.

Can someone please help me to setup my socket class properly so that i can use the instance throughout my backend and that it can succesfully emit messages to all my clients (goint to be 3)

index.js

const express = require('express')

const { createServer } = require("http")
const { Server } = require("socket.io")
const app = express()
const socket = require('./controller/socket.js');


// Initialize socket.io
const httpServer = createServer(app)
socket.connect(httpServer);

httpServer.listen(PORT, () => {
    console.log(`App listening on port ${PORT}`)
})


And my socket class in socket.js:

let connection = null

class Socket {
    constructor() {
        this._socket = null 
    }
    connect(httpServer) {
        const io = require('socket.io')(httpServer, {
            cors: {
                origin: "*",
                // origin: "http://localhost:8080",
                methods: ["GET", "POST"]
            }
        })

        io.on('connection', (socket) => {
            this._socket = socket
            this._socket.on('statusConnetion',(data) => {
                console.log(data,'date')
            })

            this._socket.on('disconnect', function () {
                console.log(socket.id,"disconnect")
            })
            console.log(`New socket connection: ${socket.id}`)
        })
    }
    emitEvent(event, data) {
        console.log('sendFromBackendAll')
        this._socket.emit(event, data)
    }
    registerEvent(event, handler) {
        this._socket.on(event, handler)
    }
    static init(server) {
        if(!connection) {
            connection = new Socket()
            connection.connect(server)
        }
    }
    static getConnection() {
        if(!connection) {
            throw new Error("no active connection")
        }
        return connection
    }
}
module.exports = {
    connect: Socket.init,
    connection: Socket.getConnection
}



backend.js file handling client request


 

const socket = require(“../controller/socket.js”)

const update_location = (req,res) => {
const connection = socket.connection()

//do update stuff

// successfully complete update

// after successful update query i want to emit so other clients can also update. The below emitEvent works but only from one client 

if(connection)connection.emitEvent(“reloadPage”)

// return res.status(200)

}

   



FRONT_END:

socket.js

import { io } from "socket.io-client";


const URL = "http://localhost:3012";
const socket = io(URL, { autoConnect: true });


and in my vue component i have my listening events:

async created() {

    socket.on("backEmit", () => {
      console.log('hi)
    });

i got two vue clients running. When i start my server both frontend client sockets connects and console prints

New socket connection: WpZ_5__1Kq5x_BHZAAAB New socket connection: s30YCZ7u1meF_2U4AAAD

When a request is submitted from one client a emit event is triggered to inform the other client to update. The problem is only one clients listening is working or it is emitting to only one client because, lets say client 1 and client 2.

When i send request from client 1, the back-end emit is triggered and client 2 hears emit and updates. Now i request from client 2 and back-end emit is triggered but then client 1 does not pick up emit event and does not update.

So only one client hears the event emitted

If anybody can help it would be great

the working client can be #2 sometimes and not #1 depending on who connected first


Solution

  • This should be your socket class. please modify it according your need and must read comments for better understanding of logic.

    let connection = null;
    
    /** Manage IO and export to use it everywhere in out backend */
    let io = null;
    
    /** Manage all user's socket
     * We need to emit event for our HTTP request that's why we need to manage all connected user's socket. so we can find user's socket by user id and emit event to that user.
     */
    let connectedUsers = {}; 
    
    class Socket {
        constructor() {
        }
        connect(httpServer) {
            io = require('socket.io')(httpServer, {
                cors: {
                    origin: "*",
                    // origin: "http://localhost:8080",
                    methods: ["GET", "POST"]
                }
            })
    
            io.use((socket, next) => {
                /** Verify user token and authorize connected client and assign user object with socket */
                socket.user = {
                    id: 1,
                    name: "John Doe"
                }
                next();
            })
    
            io.on('connection', (socket) => {
                connectedUsers[socket.user.id] = socket;
                socket.on('statusConnetion',(data) => {
                    console.log(data,'date')
                })
    
                socket.on('disconnect', function () {
                    console.log(socket.id,"disconnect")
                })
                console.log(`New socket connection: ${socket.id}`)
            })
        }
        /** Emit event to specific user */
        emitEvent(userId, event, data) {
            connectedUsers[userId].emit(event, data)
        }
        /** Emit event to all connected user */
        emitEventToAllClient(event, data) {
            io.emit(event, data)
        }
    
        static init(server) {
            if(!connection) {
                connection = new Socket()
                connection.connect(server)
            }
        }
        static getConnection() {
            if(!connection) {
                throw new Error("no active connection")
            }
            return connection
        }
    }
    module.exports = {
        connect: Socket.init,
        connection: Socket.getConnection
    }
    

    You can also save user's socketId in redis or global variable instead of connectedUsers to manage connected socket clients.

    Please up vote and approve my answer if it help