This should fix the related issue:
```
TypeError: Cannot read property 'size' of undefined
at Adapter._del (/app/node_modules/socket.io-adapter/dist/index.js:67:37)
at Adapter.delAll (/app/node_modules/socket.io-adapter/dist/index.js:83:18)
at Socket.leaveAll (/app/node_modules/socket.io/dist/socket.js:190:22)
at Socket._onclose (/app/node_modules/socket.io/dist/socket.js:334:14)
at Client.onclose (/app/node_modules/socket.io/dist/client.js:245:20)
at Socket.emit (events.js:412:35)
at Socket.onClose (/app/node_modules/engine.io/lib/socket.js:348:12)
at Object.onceWrapper (events.js:519:28)
at WebSocket.emit (events.js:400:28)
at WebSocket.onClose (/app/node_modules/engine.io/lib/transport.js:106:10)
```
A test case was added, which reproduces the issue by adding a listener
to the "leave-room" event. This does not seem to be the case for the
user reporting the issue though, which may indicate that the root cause
is elsewhere.
A few notes:
- only the first element is pre-encoded, because the other elements are
buffers and will be sent as is over the WebSocket connection
- using `socket.packet()` was unexpectedly working, we will now use
`socket.client.writeToEngine()` (see [1])
See also: 7706b123df
[1]: https://github.com/socketio/socket.io/issues/3775
This commit adds the following methods:
- fetchSockets: return the matching socket instances
- addSockets: make the matching socket instances join the specified rooms
- delSockets: make the matching socket instances leave the specified rooms
- disconnectSockets: disconnect the matching socket instances
Those methods will then be exposed by the Socket.IO server:
```js
// clear room
io.socketsLeave("room1");
// disconnect all sockets in room
io.in("room2").disconnectSockets();
// fetch socket instances in room
io.in("room3").fetchSockets();
```
This feature will also be extended in the Redis adapter to handle
multiple Socket.IO servers.
These extension points may be used by another adapter, in order to open
or close a connection to a database for example.
In Socket.IO v2, the join() method did accept a callback:
```js
socket.join("room1", () => {
io.to("room1").emit("hello");
});
```
Depending on the adapter, it may now return a promise:
```js
await socket.join("room1");
io.to("room1").emit("hello");
```
Related: https://github.com/socketio/socket.io/issues/3662
The sids and the rooms objects are now Map<string, Set<string>>:
sids => Map<SocketId, Set<Room>>
rooms => Map<Room, Set<SocketId>>
Breaking changes: the clients() and clientRooms() methods will now
return a Set instead of an array.
Also, the rooms argument in the broadcast() method will now be a Set
too.
Besides, the callbacks were removed from all function signatures, as
every operation is synchronous. Regarding the Redis adapter, the
clients() method is the only operation which will now return a promise.
This change allows us to remove the Room class, which was used to have
an external length attribute (instead of computing Object.keys()
everytime).
That method returns the list of rooms a given socket has joined. It is
intended to be used by other adapters, without them needing to access
the innards of the adapter.