Socket.io: Not able to get the list of rooms the client is currently in on disconnect event

Created on 6 Oct 2014  ·  26Comments  ·  Source: socketio/socket.io

I am trying to find the list of rooms a client is currently in on disconnect event (closes the browsers / reloading the page / internet connection was dropped) and based on my question on SO it looks like it is not possible.

I find it hard to believe that this is the case (I think this is frequently needed functionality). Can any socket.io guru tell whether this is true or even better how can I achieve this?

enhancement

Most helpful comment

+1, I would like to inform other users in the same room that someone has disconnected.

So my code would look like :

socket.on('disconnect', function() {
     socket.rooms.forEach(function(room){
         io.in(room).emit('user:disconnect', {id: socket.id});
     });
});

All 26 comments

That answer is correct, by the time the 'disconnect' event is emitted the socket has left the rooms. You can either override the onclose handler as suggested or you can store the rooms in whatever mechanism you use for your session store.

Thanks for answering this one, @yads. The disconnect event represents the situation where the socket is "out of the system".

@guille what do you think, should we make some adjustments for this use case?

+1, I would like to inform other users in the same room that someone has disconnected.

So my code would look like :

socket.on('disconnect', function() {
     socket.rooms.forEach(function(room){
         io.in(room).emit('user:disconnect', {id: socket.id});
     });
});

+1 I would also find this useful, however we would also need to make sure this happened before the empty room cleanup happens. Otherwise we run into a case where the room does not exist.

I stumbled across the same situation.

As suggested one dirty workaround is by overriding the the onclose handler.

But it would also work if socket.io would just send something like a "isDisconnecting" event right before the actually cleanup happens. This could be right before the call to this.leaveAll() in the onclose handler happens:

Socket.prototype.onclose = function(reason){
...
  this.emit('disconnecting', reason); //<--insert the new event here
  this.leaveAll();
...
  this.emit('disconnect', reason);
});

(the exports.events array has to be extended by the new eventname to get this working)

Then you can use the new event like this:

  socket.on('disconnecting', function(reason){
    var id = socket.id;
    socket.rooms.forEach(function(room){
      // For each room the user is in, excluding his own room
      if(room != id){
        console.log('Room ' + room + ': a user is disconnecting and leaving this room');
      }
    });
  });

+1, this has caused me no end of headaches in my code. It would simplify so much.

Just experienced this. Would be nice to have a disconnecting event or something along those lines.

+1, this is very frustrating

+1

+1

+1

I have the same problem to solve it. You can develop an in-memory object
where you can save socket.id (or other identifier) with rooms. In
disconnect event you can query this object to know the rooms you have to
leave.

If you are using some DB o NoSQL you can save it for distributed
environments.

Additonally, if rooms list is temporary you can clean it whit controlled
event after disconnecting.

El vie., 24 de julio de 2015 13:44, Max [email protected] escribió:

+1


Reply to this email directly or view it on GitHub
https://github.com/Automattic/socket.io/issues/1814#issuecomment-124497150
.

this is how I went to solve my problem, I simply wanted to display a count of all the users currently in a room:

var rooms = [];
io.on('connection', function(socket) {
    var room;
    socket.on('join', function(_room) {
        room = _room;
        socket.join(room);
        if (room in rooms)
            rooms[room]++;
        else
            rooms[room] = 1;
        io.to(room).emit('client joined', { clients: rooms[room] });
    });

    socket.on('disconnect', function() {
        leaveRoom();
    });

    var leaveRoom = function() {
        rooms[room]--;
        io.to(room).emit('client left', { clients: rooms[room] });
        if (rooms[room] === 0)
            delete rooms[room];
    };
});

don't know if it's any good though.

+1

plus elebenty, however did find bodyflex's implementation useful

+1

I tried this solution:

io.on('connection', function(socket) {
    console.log('CONNECT');

    socket.onclose = function(reason) {
        var roomId = socket.rooms[1];
        console.log(roomId);
        Object.getPrototypeOf(this).onclose.call(this, reason);
    }

    // ...
}

And It's works, but I have a feeling that this is not the right way

+1

Hi! I suggested here (https://github.com/socketio/socket.io/issues/2266) adding 'roomJoined' and 'roomLeft' events, would such a solution suit your needs?

server.on('roomJoined', function (id, room) {
  console.log('Socket %s has joined room %s', id, room);
});
server.on('roomLeft', function (id, room) {
  console.log('Socket %s has left room %s', id, room);
});

Your suggestion goes a little into a different direction, but will work too.
In my case I would prefer something like a new "disconnecting" event to handle different stuff in one function, when the client is disconnecting. Like in my example I posted in https://github.com/socketio/socket.io/issues/1814#issuecomment-73375702.

Well, on second thought, your solution seems cleaner to me. Please note that you may have to clone the array socket.rooms, in order to prevent any race condition:

client.on('disconnecting', function(){
  console.log(client.rooms);
  var clonedRooms = client.rooms.slice();
  setTimeout(function() {
    console.log(client.rooms); // empty array
    console.log(clonedRooms);
  }, 100);
});

It's a must have feature to have pre-disconnect event. Handling cleanup is much harder without this.

I am currently overriding the onclose handler, would love a solution to this. My override is as simple as emitting the disconnect event before leaving the rooms.

I also added a disconnecting event that fires before disconnect and came to submit a PR to find that someone had already submitted a PR with nearly identical code :). +1 for PR #2332 !

You don't need to add events, you need to store all the connected sockets into an associative array with keys being the socked IDs. Then, on 'disconnect', you retrieve the room for that socket ID.

let sockets={};
let rooms={};

io.on('connection', function(socket) {
    sockets[socket.id]={
        room:<whatever>
    }

    socket.on('disconnect', (reason) => {
        let room=sockets[socket.id].room;
        io.to(room).emit('message', {
            message: 'I'm out!'
        });
        delete sockets[socket.id];
    });
}

Hello everyone, how I was able to solve this was like so:

socket.on(disconnecting,()=>{
const rooms = Object.keys(socket.rooms);
io.to(rooms[1]).emit("event", "message");
});

Thanks, hope it helps someone

Was this page helpful?
0 / 5 - 0 ratings