socket.io icon indicating copy to clipboard operation
socket.io copied to clipboard

Emit to room not work with uWebsocketjs

Open SaltFish001 opened this issue 1 year ago • 7 comments

Describe the bug Emit some message to room not work with uWebsocketjs, but clients does`t got any message. To Reproduce

Please fill the following code example:

Socket.IO server version: x.y.z

Server

import { Server as socket_server } from 'socket.io';
import { App } from 'uWebSockets.js';

const uapp = App();
const socket_instance = new socket_server({
  path: '/socket',
});
socket_instance.attachApp(uapp);
socket_instance.use((scoket, next) => {
  console.log('socket connect >>>', scoket.id);
  scoket.join('test');
  setTimeout(() => {
    console.log('socket emit >>>', scoket.rooms);
    socket_instance.to('test').emit('message', 'hello world');
  }, 2000);
  return next();
});

uapp.listen(9999, (token) => {
  console.log(token);
  console.log('server is listening on port 8888');
});

Socket.IO client version: x.y.z

Client

import { io } from 'socket.io-client';
const client = io('http://localhost:9999', {
  path: '/socket',
  transports: ['websocket'],
});

client.onAny((...arg) => {
  console.log('onany >>>', arg);
});
client.connect();

Expected behavior A clear and concise description of what you expected to happen.

Platform:

  • Device: [e.g. Samsung S8]
  • OS: [e.g. Android 9.2]

Additional context Socket.io & Socket.io-client 4.7.5 uWebsocketjs 20.44.0

SaltFish001 avatar Jul 18 '24 10:07 SaltFish001

Hi! I was indeed able to reproduce the issue.

It does not seem to happen with uWebSockets.js#v20.30.0 though, this needs some additional investigation.

darrachequesne avatar Jul 22 '24 09:07 darrachequesne

Hi! I was indeed able to reproduce the issue.嗨!我确实能够重现这个问题。

It does not seem to happen with uWebSockets.js#v20.30.0 though, this needs some additional investigation.然而,这种情况在 身上似乎并未出现,这需要进一步的调查。

Thanks reply. Right now I can use fetchSockets get all socket , then foreach sockets to emit event. Hope this is not a hard work for you.

SaltFish001 avatar Jul 22 '24 13:07 SaltFish001

I think I found the cause of this bug.This is because during the execution of the middleware, the socket has not yet been added to the adapter's namespace.

const { Server: socket_server } = require("socket.io");
const { App } = require("uWebSockets.js");

const uapp = App();
const socket_instance = new socket_server({
  path: "/socket",
});
socket_instance.attachApp(uapp);
socket_instance.use((scoket, next) => {
  console.log("socket connect >>>", scoket.id);

  // console.log adapter's namespace
  console.log(scoket.adapter.nsp.sockets, '----');
  scoket.join("test");

  setTimeout(() => {
    console.log("socket emit >>>", scoket.rooms);
    socket_instance.to("test").emit("message", "hello world");
  }, 2000);
  return next();
});

uapp.listen(9999, (token) => {
  console.log(token);
  console.log("server is listening on port 9999");
});

image

when call the scoket.join("test"), it's actually call: https://github.com/socketio/socket.io/blob/582655f679ccc43f0a9cbef1f13ea3cde07dc2e1/packages/socket.io/lib/socket.ts#L554-L561

when the socket_instance.attachApp is called, the Adapter.prototype.addAll would be rewrite: https://github.com/socketio/socket.io/blob/582655f679ccc43f0a9cbef1f13ea3cde07dc2e1/packages/socket.io/lib/uws.ts#L14-L33

this bug happend here, we can't find the socket in the nsp now, so it's just return and didn't call the subscribe fun.

const socket: Socket = this.nsp.sockets.get(id); 
 if (!socket) { 
   return; 
 } 

and why we can't get the socket by id from the nsp here is due to the execution order of the middleware and _doConnect method. https://github.com/socketio/socket.io/blob/582655f679ccc43f0a9cbef1f13ea3cde07dc2e1/packages/socket.io/lib/namespace.ts#L334-L357

The _doConnect method will only be executed when all the middleware has been executed, which track the socket.

TXWSLYF avatar Aug 07 '24 09:08 TXWSLYF

for the example below, we don't use uWebsocketjs this time, even if the socket has not yet been added to the adapter's namespace, it also works well.

const { Server: socket_server } = require("socket.io");

const socket_instance = new socket_server({
  path: "/socket",
});
socket_instance.use((scoket, next) => {
  console.log("socket connect >>>", scoket.id);
  console.log(scoket.adapter.nsp.sockets, '----');
  scoket.join("test");

  setTimeout(() => {
    console.log("socket emit >>>", scoket.rooms);
    socket_instance.to("test").emit("message", "hello world");
  }, 2000);
  return next();
});

socket_instance.listen(9999, (token) => {
  console.log(token);
  console.log("server is listening on port 9999");
});
image

this is because by default, the join method use the in-memory-adapter,it don't check if the socket exists now but just store the relation. https://github.com/socketio/socket.io/blob/582655f679ccc43f0a9cbef1f13ea3cde07dc2e1/packages/socket.io-adapter/lib/in-memory-adapter.ts#L87-L104

and get the socket when emit message. https://github.com/socketio/socket.io/blob/582655f679ccc43f0a9cbef1f13ea3cde07dc2e1/packages/socket.io-adapter/lib/in-memory-adapter.ts#L333-L358

TXWSLYF avatar Aug 07 '24 09:08 TXWSLYF

I created a fix but don't know if it will have any other impacts, would appreciate if you could check it.

TXWSLYF avatar Aug 07 '24 09:08 TXWSLYF

@TXWSLYF thanks for the analysis :+1: There is indeed something wrong when calling socket.join() in a middleware.

io.use((socket, next) => {
  socket.join("test");
  next();
});

io.on("connection", (socket) => {
  io.to("test").emit("hello"); // should work
});

That being said, I'm not sure the following should work, since the socket is not connected yet:

io.use((socket, next) => {
  socket.join("test");
  io.to("test").emit("hello"); // should it really include the socket?
  next();
});

I'm looking into this.

darrachequesne avatar Sep 20 '24 05:09 darrachequesne

I had the same issue here, but after upgrading to version 4.8.0 it seems to have been fixed

gkourpa avatar Sep 29 '24 16:09 gkourpa

For future readers:

This should be fixed by https://github.com/socketio/socket.io/commit/b04fa64365729244a9c50a6b54b12e9bcc9e55d0, included in [email protected].

darrachequesne avatar Oct 22 '24 06:10 darrachequesne