MUHAMMAD Siyab
MUHAMMAD Siyab

Reputation: 446

Socket.io: Events firing twice if used inside an express route

I'm working on a chat app in socketio. The issue i'm stuck in is that if i put my io.on('connection', ..}) block outside the express route app.get('/chat'), everything works fine but when i put it inside the route /chat. everything inside the connection is firing twice.

server.js

 // On new connection
 io.on("connection", socket => {
      console.log('Socket ID: ' + socket.id);
      // I want the user object (inside /chat route) to be available here..
 })

// @route:chat
app.get("/chat", auth, async (req, res) => {
    const user = User.findbyId(req.userId);
    // socket.io part moved outside the route

    res.render('chat', {})
})

Output on first request to /chat:

Socket ID: 5e82d1a21c9d4400003e9bce

Output on second request to /chat:

Socket ID: 5e82d1a21c9d4400003e9bce --> this is repeating
Socket ID: 5e82d1a21c9d4400003e9bc4

And so on if i keep requesting /chat.

Any idea how to solve this issue?

Upvotes: 0

Views: 418

Answers (1)

i.brod
i.brod

Reputation: 4603

Generally, socketIO operations shouldn't depend on an express route. If you want a user to join the socketIO connection, it should be done via SocketIO's event handlers. Your front-end should initiate the connection, and pass some identity to SocektIO, if you want to associate a "user" to that socket.

I don't know how your application handles auth, but a common practice is to pass a token to the SocketIO connection establishment:

const socket = IO.connect('http://localhost:8000', {
    query: {
      token//This token will be available on the server.
    }
  });

So then in your server:

const middleware = async (socket,next)=>{
    const token = socket.handshake.query.token;//Now you have the user token, which presumably contains the user ID.

    const verifiedUser = await getUserByToken(token);//Let's say this returns a user object, if the token is valid, false if not.
    // Let's assume that behind the scenes this function also calls User.findbyId(id);

    if(verifiedUser){
        socket.userObject = verifiedUser;//You can place the userObject on the token object, to be used later.
        next()//Will allow the "connection" event to proceed.
    }else{
        next(new Error('INVALID_CREDENTIALS'))//Will cause the on("error") event to fire in the front-end, passing this error.
        //The on("connection") event here will not fire.
    }
}

io.use(middleware)

io.on('connection', async (socket) => { 

    //This runs only if middleware is "successful".


})

I don't know if this really answers your questions, but it's an example for how a socket-user relationship might look like.

Upvotes: 1

Related Questions