Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

socket io rooms names and number of users inside specific room

I'm trying to build some basic chat (based with rooms) using socket.io versions:

"socket.io": "^2.1.1"
"socket.io-client": "^2.1.1"

I have a few basic questions that I couldn't find any working answers no matter how deep I looked for them.

  1. When a user gets in a specific room I'm doing it (in the server) socket.join(roomName) so the room 'exists' only if there is at least on socket connected to this room ?

  2. I want to create a screen with the rooms name and the number of the participates - (is it possible to get it by the client side socketIO's object ?), I found that it's possible to get the rooms names(server-side) by using io.sockets.adapter.rooms but I get really weird strings which are definitely not the room names.

  3. I'm trying to create a page inside each room that shows the users that are connected to that room (connection that got into a room with socket.join(roomName))

I'm new to socket.io I hope someone can help me to understand better how to work with that, and what I'm missing in here.

thanks!

like image 238
greW Avatar asked Oct 22 '18 20:10

greW


2 Answers

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.

like image 132
Preview Avatar answered Oct 21 '22 06:10

Preview


  1. Yes a room only exists if it has at least one member, and calling socket.join(roomName) will create one if there currently isn't any.

  2. Okay so checking io.sockets.adapter.rooms is the way to check that internally, only the weird strings you're seeing are socket IDs since (from documentation): 'For your convenience, each socket automatically joins a room identified by its id (see Socket#id). This makes it easy to broadcast messages to other sockets' socket IDs tend to look something along the lines of: 'PZDoMHjiu8PYfRiKAAAF'

    If you just want a list of your rooms, you'll need to keep track of room names that you defined and not rely on the socket.io state.

  3. Getting a list of sockets that are connected to a room would be done as follows:

    let socketsOfRoom1 = io.sockets.clients('chatroom1');
    let numberOfClientsInRoom1 = socketsOfRoom1.length;
    
    console.log(numberOfClientsInRoom1);
    socketsOfRoom1.forEach((socket) => {
        console.log(socket)
    });
    
like image 21
Dennis Ruiter Avatar answered Oct 21 '22 08:10

Dennis Ruiter