My discovery about the bug with Socket.rooms and how I found the current socket.rooms
See original GitHub issueBug description
Hi,
I am an enthusiast in Socket.io. At the moment, I would like to report a bug in version 2.x of socket.io, where the main impacted factor is rooms (which used to be io.sockets.rooms) but got changed in version 2.x. It is not deprecated and you can still access it, however through a very long chain of javascript object properties.
This error happens when I’m using a namespace.
I’ve dug into the socket source code and found a problem here. If you have installed node modules via npm (or yarn), you can find the file in ./node_modules/socket.io/lib/socket.js. In the function join
Socket.prototype.join = function(rooms, fn){
...
var self = this;
...
this.adapter.addAll(this.id, rooms, function(err){
rooms.forEach(function (room) {
console.log('each room in rooms----------', room);
self.rooms[room] = room;
}
console.log('This socket after setting rooms--------', self.adapter); // (****)
...
});
return this;
Note: All of the console.log() I mention are added by me.
If you take notice, in this function, we are adding each element of the rooms array to self.rooms. However, this is not the socket.rooms that we expect but a very different room. I’ll explain how we actually reach this room later.
Assume, in a real-life scenario, I want a socket to join after it has connected. Taking a look at the 'onconnect function in the socket.js file, which is always fired before the join function. Here is the code for the onconnect function:
Socket.prototype.onconnect = function(){
...
console.log('in onconnect funtion', this.id);
this.join(this.id);
...
};
Here is where the problem arises. When we connect, we actually “join” this.id, thus making this.id become an unexpected room. From the console.log (****) that I added to the function join, you can see inside the property rooms:
rooms:
{ '/namespace_name#x9Je6cweXBB5fp4eAAAB': Room { sockets: [Object], length: 1 },
'/namespace_name#pMr_xrIEM2lSc182AAAC': Room { sockets: [Object], length: 1 },
'/namespace_name#BscQZyK_gFrIL_2-AAAD': Room { sockets: [Object], length: 1 },
'/namespace_name#C5WH4nJo_73ZVvGDAAAE': Room { sockets: [Object], length: 1 },
room_name: Room { sockets: [Object], length: 1 } },
room_name is the name of the room that I used for socket.join(“room_name”)
You can see that I have a lot of extra, unexpected rooms that are automatically added when my socket connects.
How to find the current rooms
Assume you use a namespace
console.log('Room list that contains connected rooms', util.inspect(io.sockets.in('namespace_name').adapter.nsp.server.nsps['/namespace_name'].adapter.rooms, {showHidden: false, depth: 2, colors: true, }));
Ps
I have discovered this problem when I tried to find a list of all available connected rooms with socket.io. In versions before 1.0, we could do it with socket.rooms and we would have an array of room_name. However, in this 2.0 function, I cannot find any effective method that wouldn’t require a lot of steps to actually find a list of different rooms that have been connected. Can you give my a way to fetch all room names in the version 2.x (socket.rooms will not work)?
And should there be a way to filter rooms so that no duplication is made if there are many sockets connecting to the same room?
Tl,dr: Onconnect function in socket library adds redundant rooms to the room list by using the function join, and the rooms, which used to be found in socket.rooms, can be found in a different place.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:2
- Comments:6 (1 by maintainers)
Top GitHub Comments
Has this been resolved yet? I don’t understand why having a client connect to a namespace creates a “room” of the user in that namespace.
@allicanseenow :
The socket.io documentation clearly states:
My understanding is that namespaces contain rooms, but are not rooms themselves. Like a one-to-many relationship.
Rooms aren’t appearing under namespaces correctly either, which seems to contradict the documentation and what @spietrek87 mentioned about referencing the adapter.
In a app I’m working on, when a client joins a namespace called
/project
they automatically enter a room named after the project ID they’re viewing. Several of these projects exist such as “Project A” / “Project B” / etc.When a client on Project A joins the namespace, this should create a room named “Project A” underneath the namespace of
/project
.Here’s a code snippet:
server.js
someReactComponent.js
Inside server.js,
console.log(io.nsps['/project'].rooms)
should return["Project A"]
, but contains[]
instead.Upon checking the adapter for the
/project
namespace by console.loggingio.nsps['/project'].adapter.rooms
, there are two rooms.One is correctly named ‘Project A’ while another unexpected room is ‘/project#GUyI-6I3ktZusTJsAAAA’'.
It appears the second room should NOT be appearing as @allicanseenow stated.
I’d love to see this bug fixed, otherwise it prevents the room / namespace distinction from existing and prevents this package from being useful.
If I’m just understanding socket.io incorrectly, please let me know. Thanks in advance!
For future readers: as of Socket.IO v3, the
socket.rooms
attribute is basically a reference to the underlying adapter, which stores the relationships between Socket IDs and rooms.Documentation: https://socket.io/docs/v3/rooms/#Implementation-details
Source: