Skip to content

Ability to get all clients for a given room #1428

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 2 commits into from

Conversation

crickeys
Copy link
Contributor

Not sure if I fully understand all the parts to the new socket 1.0, but I needed this ability. I believe I separated the parts into the namespace and adapter correctly, but please do check me over. Thanks!

@Ijatsu
Copy link

Ijatsu commented Feb 20, 2014

I'm new and I don't want to mess, but this function seems to already exist:
https://github.com/LearnBoost/socket.io/wiki/Rooms

@chriskilding
Copy link

+1 for @Ijatsu - just for completeness, here's how you do it word for word from the wiki:

"If you want a list of clients in a particular room, call io.sockets.clients('room'). This will return Socket instances of all clients in the room."

Is there anything this method doesn't do that you need @crickeys?

@rauchg
Copy link
Contributor

rauchg commented Feb 21, 2014

I'll merge this. Just need code style fixes and tests

@chriskilding
Copy link

@crickeys I noticed yesterday that the Adapter was ripped out of socket.io core and put into its own repo at https://github.com/LearnBoost/socket.io-adapter - you may need to update your PR accordingly

@gtramontina
Copy link

Any updates on merging this? Much needed. :-)

@rauchg
Copy link
Contributor

rauchg commented May 23, 2014

What's your usecase specifically @gtramontina ? I'm curious because I've always been fine with join and leave, and emitting to rooms.

@gtramontina
Copy link

I'm rewriting a collaborative whiteboard I've written a few years ago.
The idea is once a new person comes in, the server asks any (or the last) user for the current board status (basically a png base64 copy). I thought of doing something like:

socket.on('connection', join);
function join (socket) {
  // ...
  var room = socket.request._query.room; // the underscore here was already a bit tricky :-)
  var lastParticipant = this.sockets.clients(room).last(); // .last() here just for the sake of brevity
  lastParticipant.emit('get snapshot');
  lastParticipant.on('snapshot', function (canvas) { ... });
  // ...
}

Do you see a better way of achieving this, or even a completely different approach? I'm trying not to have much state on the server side...

@Canop
Copy link

Canop commented May 29, 2014

The fact this doesn't seem necessary is puzzling. Is there a better way to list the connected users in a room ? Or to emit a message to only some sockets in a room ?

@ismarslomic
Copy link

#1544

@julianlam
Copy link

Was looking to drop in v1.0 into NodeBB, although we use var clients = io.sockets.clients(roomName); to determine who's in a room (to update the list of users in a given topic, in real-time). Would appreciate this method added back.

We're also referencing .roomClients() to determine room status per client: io.sockets.manager.roomClients[socket.id]

@alexiskattan
Copy link

+1

@FREEZX
Copy link

FREEZX commented Jun 5, 2014

Here's my use case. I have a calling system which should only send call message to one tab of one user. Each socket is joining a room named like the user id.
On the server side am using cluster workers, each running a separate socket.io instance.
I would normally emit to the socket's own room, but the problem is, due to the clustering, the target user might be connected to another worker, and so in the worker handling the request, i have no way of knowing which socket to emit to (I have neither the socket nor the socket id).

In 9.x i was using redis (to be able to work with multiple worker processes) and i was calling io.sockets.clients(userId), which seemed to be correctly returning all sockets connected to the room named like the user id, and i was just picking the last socket and sending the message there.

@FREEZX
Copy link

FREEZX commented Jun 5, 2014

Also, the ability to manually disconnect specific clients in a room from the server side was useful.

@vit-lebediev
Copy link

This is really frustrating that there is no way to get a list of all connected users. Previously we did it by
io.sockets.clients().
My usecase is similar to @FREEZX, but instead of creating a room for each connection, we just added unique data into handshake data, and then, iterating over clients list, determined which client should be notified.
So my question is: how to get a list of connected clients?

@ismarslomic
Copy link

@Malgin, have you seen solution in #1544?

@Canop
Copy link

Canop commented Jun 6, 2014

It looks like all developpers have made a similar workaround function. It's just sad this common function isn't standard, especially as it was before.

@vit-lebediev
Copy link

@ismarslomic Thanks, that is helpful information, but it did not solve my issue. I do not use specific rooms, just 'default' one. And from this post I understand that default room is ''.
But when I try to get all clients by:

var clients = io.sockets.adapter.rooms[''];
console.log(clients);

I get 'undefined'

@ismarslomic
Copy link

Ok. So what you really want know is number of connected socket to server:
io.sockets.sockets.length

@tscheurer
Copy link

My use case is similar to @julianlam. I’d like to update a list of connected room-users in real-time.

@ismarslomic
Copy link

Well, if you are not joining particular room then counting connected clients at server can been done be getting length of socket array like I described above. Does this solve your use case?

@Canop
Copy link

Canop commented Jun 6, 2014

@tscheurer Is that what you want : http://stackoverflow.com/q/24059287/263525 ?

@vit-lebediev
Copy link

@ismarslomic Thanks, but I just don't see how the number of connected sockets will help me identify specific socket.
What I need is ability to iterate over all connected sockets, and read it's handshake data.

@tscheurer
Copy link

I’m currently creating an old-fashion room-based chat. Users can just enter a nickname and join a room.

I’m going to store the nickname on the socket. If a client requests the list of the users in the current room, I’m going to take the list from io.sockets.clients(roomName)and iterate through it, in order to send all the nicknames to the requesting client.

A possibility would be to handle the users in a room by myself, but until I moved to 1.0 it was working fine with io.sockets.clients(roomName).

@Canop: so far i was doing it as suggested in the answer on stackoverflow.

@catearcher
Copy link

Pretty strange behavior:
console.log(io.sockets.adapter.rooms[roomName]) logs an array with 3 entries. Using _.isArray I confirmed that this is, in fact, an array.

This however: io.sockets.adapter.rooms[roomName].length returns 0.

Iterating over the array using _.each or Array.prototype.forEach does not work either. The only thing that does work is using a for-in loop.

@pravincar
Copy link

So if I broadcast to a room with the redis adapter does it get sent to connected sockets on all nodes? Or is that not implemented as well?

@rauchg
Copy link
Contributor

rauchg commented Jun 13, 2014

@pravincar if you're using socket.io-redis all broadcasts reach all connected clients in every node ;)

@rauchg
Copy link
Contributor

rauchg commented Jun 13, 2014

The main reason I didn't want local-only clients() is precisely to avoid this confusion haha

@rauchg
Copy link
Contributor

rauchg commented Jun 13, 2014

Are you fine with clients giving you guys the array of ids? It won't give you Socket objects.

@pravincar
Copy link

I see :) @guille Totally fine with the array of ids.. as long as you're giving it to me tonight, I'll bow down to you :P Demo tomorrow and my app can't work if I don't know who's connected

@rauchg
Copy link
Contributor

rauchg commented Jun 13, 2014

If you need a quick workaround for now you can always query redis. We'll get this out asap, but today we're making a patch release first with a few little but important bugfixes. Then this is going to be in the next release 1.1.0

@pravincar
Copy link

Cool. Will do that for now. Thanks!

On Fri, Jun 13, 2014 at 11:18 PM, Guillermo Rauch [email protected]
wrote:

If you need a quick workaround for now you can always query redis. We'll
get this out asap, but today we're making a patch release first with a few
little but important bugfixes. Then this is going to be in the next release
1.1.0


Reply to this email directly or view it on GitHub
#1428 (comment).

@pravincar
Copy link

What is the key in redis where I can find this? Am unable to locate this.

@gtramontina
Copy link

Hum... given the ID, is there a way to target that specific connection and send it a message? Something like: find the socket from an ID and .send on it?

@pravincar
Copy link

@gtramontina Every connection is automatically assigned to a room which is identified by its socket id. So you can do socket.to(socketid).emit(event)

@gtramontina
Copy link

then perfect! :-)

@FREEZX
Copy link

FREEZX commented Jun 14, 2014

@guille Client ids seem like an ok solution for the given use cases.
Any idea how to go about disconnecting specific clients from any node on the server side though?

@FREEZX
Copy link

FREEZX commented Jun 17, 2014

I wrote the code for the clients function to retreive the ids of sockets in a given room.
Related pull requests:
#1630
socketio/socket.io-adapter#5
socketio/socket.io-redis-adapter#15

@julianlam
Copy link

Didn't this PR already have commits?

@FREEZX
Copy link

FREEZX commented Jun 17, 2014

My PRs makes it async so it can also work with redis, across nodes

@pravincar
Copy link

Looks good to me. Will test it out and give you feedback.
Was thinking of another use case. Lets say when a user enters a chat room, I want to show him a list of users in the room (username, name, some stats), it would be useful to have some meta information apart with the socket id.
It would be probably better to push a json into redis of the form {socketId:id,name:'abc',username:'Me'} with keys that the user can specify.

@julianlam
Copy link

@pravincar I am of the opinion that it should be as lean as possible. It's trivial to do an async.map to get the meta data you need after retrieving the ids

@rauchg
Copy link
Contributor

rauchg commented Jun 17, 2014

@FREEZX I commented on your PR with regards to the signature

@rauchg
Copy link
Contributor

rauchg commented Jun 17, 2014

We'll follow the discussion in @FREEZX's PR

@rauchg rauchg closed this Jun 17, 2014
@FREEZX
Copy link

FREEZX commented Jun 19, 2014

@pravincar Something like the old client.get and .set methods would make sense, but given the fact that you cannot directly access sockets of other nodes, i don't think that would be useful at the moment. Now you could keep your own data structures associated with the socket id.

@mikaturunen
Copy link

👍

@akashkrishnan
Copy link

👍

@robbennet
Copy link

Why has this not been implemented yet?

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.