简体   繁体   中英

Loop over unique Socket.IO rooms to emit unique data to each room in NodeJS

I am creating rooms by allowing the client to pass their room name:

io.on('connection', socket => {
  socket.join(socket.handshake.query.roomName)
})

Let's just say three sockets connect, and the room names are 1, 2, and 3. I want to be able to do something like:

listOfRooms.forEach(sendSomeData)

sendSomeData(room, index){
    let data = getSomeData(room)
    io.in(room).emit('data', data)
}

Where getSomeData(room) generates different data depending on the name of the room passed to it.

Is there any built in way to get a list of all rooms in the root namespace or for that IO instance without setting up a data structure to manage it?

Yes I could just create an array and append to it every time a new connection occurs but it seems like a lot of extra work to manage if two sockets join the same room, I don't want my array to have duplicates, but I can't both get rid of duplicates, and delete the object from the array when one socket disconnects...

You probably don't want to send to a list of all rooms in the namespace because socket.io creates a room for every connected user and you don't want to send to all of those.

You can get an object that contains all the rooms in a namespace (as property names on an object) like this:

let roomsObject = io.of("/").adapter.rooms

Or, just get all the rooms like this:

let allRooms = Object.keys(io.of("/").adapter.rooms);

So, then you just need to be able to tell which rooms are ones you added and which ones are ones that socket.io added automatically for each connected socket. The simplest way I can think of is for you to always add some sentinel character to the start of any rooms you create such as an underscore.

io.on('connection', socket => {
  socket.join("_" + socket.handshake.query.roomName)
});

And, of course, anywhere else you refer to the room name, you need to make sure it has the appropriate "_" on the front or if you're showing room names to the user, then you need to remove it.

Then, you can tell the difference between your room names and the socket.io room names:

let myRooms = Object.keys(io.of("/").adapter.rooms).filter(room => room.startsWith("_"));

Now, you can iterate that list of rooms:

for (let room of myRooms) {
    io.of("/").to(room).emit(...)
}

Note: in this answer, I showed io.of("/") to indicate how you specify the namespace you want to use (because you explicitly mentioned a namespace object), but if you're just using the default namespace, you can just to io.to("room").emit(...) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM