Skip to content

Add the "loopback" flag. #3235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Conversation

ripfester
Copy link

@ripfester ripfester commented May 3, 2018

The kind of change this PR does introduce

  • a bug fix
  • a new feature
  • an update to the documentation
  • a code change that improves performance
  • other

Current behaviour

It is not possible to send messages to the local (server) endpoint. In scenarios where rooms/broadcasts are used, this requires the server to maintain a separate room->socket mapping so that administrative actions can be performed (e.g., close all sockets in room 'foo').

New behaviour

With this change (and related PR socketio/socket.io-adapter#56), it is possible to emit/broadcast messages that are handled by the local (server) endpoint by inserting .loopback into the emit syntax. On connect, the server can add handlers for messages that originate server-side, and later broadcast those messages in order to effect administrative actions (e.g., close all sockets in room 'foo') without maintaining independent mappings.

Other information (e.g. related issues)

socketio/socket.io-adapter#56 must be committed before this change, as socket.io-adapter is used in tests and must honour the loopback flag.

The "loopback" flag is used to emit messages on the local endpoint of
a socket; e.g., allowing the server to send a message to the server's
handler directly.

This is especially useful in conjunction with rooms, as it allows the
server to proactively trigger behavior for each socket in a room without
having to maintain a separate list of said sockets or relying on the
client endpoint to trigger the behavior.
@chris-codaio
Copy link

Would it be possible to pull this in? Would be useful.

@darrachequesne
Copy link
Member

this requires the server to maintain a separate room->socket mapping so that administrative actions can be performed (e.g., close all sockets in room 'foo').

Couldn't you just do the following?

const room = io.of('/').adapter.rooms['foo'];
const sockets = room.sockets;

for (var id in sockets) {
  if (sockets.hasOwnProperty(id)) {
    const socket = io.of('/').connected[id];
    if (socket) {
      socket.disconnect();
    }
  }
}

Well, you're accessing the adapter internals, but that should work, shouldn't it?

@chris-codaio
Copy link

That won't work when you're using something like socket.io-redis, will it?

@ripfester
Copy link
Author

It's been a couple of years, but if I recall correctly @chrisleck is correct. This functionality was specifically desired to allow these types of server-side actions to be generated on a single server and distributed/handled across multiple servers when using the redis adapter.

@darrachequesne
Copy link
Member

Would customHook/customRequest from the Redis adapter suit your needs? (there's not much documentation about this feature, I'll try to fix this)

@chris-codaio
Copy link

Hi @darrachequesne, I took a look at the customHook/customRequest function, but it looks like that doesn't allow for sending to individual rooms? Or am I reading that incorrectly?

@chris-codaio
Copy link

Hi @darrachequesne, I'm not trying to be annoying, but would like to make some forward progress here if possible. Any feedback on my comment above regarding sending to rooms through the custom* functions you pointed out above?

@chris-codaio
Copy link

Any updates @darrachequesne ?

@chris-codaio
Copy link

Hello folks - any updates on taking this PR?

@darrachequesne
Copy link
Member

@chris-codaio sorry for the delay.

If I correctly understand the suggested change, there is no way to make a distinction between packets sent by the client-side and those sent by the server-side, which seems problematic. Or am I missing something?

This commit (which will be released in the next version of Socket.IO) adds the following methods:

// return all Socket instances of the "admin" namespace in the "room1" room
const sockets = await io.of("/admin").in("room1").fetchSockets();

// make all Socket instances of the "admin" namespace in the "room1" room join the "room2" room
io.of("/admin").in("room1").socketsJoin("room2");

// make all Socket instances of the "admin" namespace in the "room1" room leave the "room2" room
io.of("/admin").in("room1").socketsLeave("room2");

// make all Socket instances of the "admin" namespace in the "room1" room disconnect
io.of("/admin").in("room1").disconnectSockets();

Would it suit your use case?

If it does not, I think we could indeed add the loopback flag, but at the namespace level instead:

// main namespace
io.loopback.emit("hello");
io.on("hello", () => { /* ... */ });

// custom namespace
io.of("/admin").loopback.emit(/* ... */);
io.of("/admin").on(/* ...*/);

// maybe with acknowledgements too, in a multi server setup
io.loopback.emit("hello", 1, "2", (err, responses) => {
  // ...
});
io.on("hello", (arg1, arg2, cb) => {
  cb(42);
});

What is your opinion?

@darrachequesne
Copy link
Member

For future readers: this was implemented with the serverSideEmit feature.

Documentation: https://socket.io/docs/v4/server-api/#namespace-serverSideEmit-eventName-%E2%80%A6args-ack

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants