Indeed, a socket.io room only exists as long as there is one client connected to it. Additionally, it is destroyed to free up memory once the last client leaves it as shown here in the socket adapter:
if (this.rooms[room].length === 0) delete this.rooms[room];
To get the real room names, you will have to keep track of them on the server side. The easiest way would be an object of user counts indexed by rooms names.
const usersByRooms = {}
You would first send this full object when a new socket connects
socket.emit('getAllRooms' usersByRoom)
And iterate on this object by its keys when you receive it on the client
socket.on('getAllRooms', (usersByRoom) => {
Object.keys(usersByRoom).forEach(roomName =>
console.log(roomName, usersByRoom[roomName]))
})
I'm assuming your page would need to have the number of clients connected to your room updated live. For this, you need to have a method to broadcast the number of users of a room if it were to change, and updating your usersByRooms cache accordingly, like this:
const updateCount = roomName => {
const userCount = io.sockets.clients(roomName).length
// we do not update if the count did not change
if (userCount === usersByRoom[roomName]) { return }
usersByRoom[roomName] = userCount
io.emit('updateCount', { roomName, userCount })
}
This method needs to be called every-time a socket joins and leaves a room successfully by using the callback of these two methods:
socket.join(roomName, () => {
updateCount(roomName)
})
socket.leave(roomName, () => {
updateCount(roomName)
})
You could now hook into the new disconnecting event added in socket.io#2332 in case your client disconnects or simply closes your application to broadcast the new count to any room the socket was connected to.
socket.on('disconnecting', () => {
const rooms = socket.rooms.slice()
// ...
})
This approach might be a little tricky as you would need to keep track of the rooms of the socket being disconnected and update them right after the socket completed the disconnection.
A simpler method would be to iterate over all the rooms right after every socket disconnection and call the updateCount, since the method only broadcasts an event if the user count of the room changed, it should be fine un less you have thousands of rooms.
socket.on('disconnected', () => {
Object.keys(usersByRooms).forEach(updateCount)
})
Please note that it gets a bit tricky if you are using a socket cluster, but I'm assuming a normal setup.