Socket.io - Emit to array of socket id - node.js

I have socket id of each connected user stored in my database. When any user posts a comment or status, I want to broadcast the same to all his/her connections using socket id stored in my database.
I can emit the message to individual client using his/her socket id by using io.sockets.connected[ socket.id ].emit('privateMsg', 'Hello! How are you?');
But how do I emit the same to the array of socket id which i have generated using select query from my database.

You can use concept of rooms. Whenever a socket connection arrives, join the connections to a room. And on disconnect, remove the socket from the room.
socket.on('connection', function () {
socket.join('room1');
});
socket.on('disconnect', function () {
socket.leave('room1');
});
Now when you want send messages to sockets connected on a room, you can broadcast it to room.
socket.broadcast.to('room1').emit('eventName', data);

You could dynamically create a room for each socket that connects and emit to it without having to loop over the entire array every time. Like so:
socketids.foreach(function(socketid){io.sockets.connected[socketid].join(sendingSocket.id);});
Then you can emit to those sockets from your sending socket by doing the following:
sendingSocket.to(sendingSocket.id).emit('publicMessage', 'Hello! How are you?')
As a side-note, I don't think keeping socket ids that change in a database is the best approach, since they have no persistence at all. You may want to try to find a better identifier for your database.

For anyone who visites this thread. After Socket.io 3.x we can pass arrays of room names and socket ids to io object. like this:-
socketIds = [xlksdf09sdfsk,sdosdifns90sdf,..........]
io.sockets.to(socketIds).emit('hello','recieving all sockets')
roomNames = [roomA,roomB]
io.to(roomNames).emit('hello','recieves each member of the rooms')
// Event is also not emmitted multiple times on the client side
// evern if single socketId is present in multiple rooms.

Related

socket.io emit not working for current user who sends it but working for all other users in the room

I have a socket running in my node application where I'm emitting an update event that updates the number of users in a room to all the clients. But the problem is that it is updating the count for all the users instead of the user who emitted it. I also want the update for the current user. Here is the code:
// emitting to update the poeple count
socket.to(roomId).emit('update-user-count', io.sockets.adapter.rooms.get(roomId).size)
// listening to update the people count
socket.on('update-user-count', (size) => {
console.log('user count update emitted')
document.querySelector('.extras--people--count').textContent = `${size} People`
})
Seems like io.emit() is the solution to broadcast the message to all the users in a room. More in here: Broadcasting in Socket.io Rooms in Socket.io

How does socket.to(username).emit('eventName',{}) work?

Can someone please explain how does socket.to(username).emit('eventName',{}) work? Basically I want to know how it identifies the 'username' is logged in or not.
socket.to(room).emit(...) will emit messages to all the users that joined room using: socket.join(room).
By default, each socket joins a room identified by the socket id, that's why, you can also do: socket.to(socketId)
Without knowing your logic, username room will be empty if the user isn't logged in, and it will have the logged user if the user is online. Socket.io doesn't really know if the user is online or not, it only knows that there is an user in that room.
io.on('connection', (socket) => {
console.log('New user connected');
const username = getUsernameSomehow(); // logged user, ip, cookie, or whatever you like
// When the user is online, it will join to
// a room named after his username
socket.join(username);
socket.on('send', (message) => {
console.log(message);
// Now you can send a message by only knowing the username
socket.to(message.target).emit('message', message.text);
});
});
If you don't join the user to username room, your code will never work.
First of all, it's not a username, it's a socket.id value or a room name that works in:
socket.to(roomname).emit(...)
The way it works is very socket that connects to your server is given a socket.id value and then that value is then added to a data structure the socket.io server keeps. Any times a socket disconnects that socket.id is removed from the data structure.
So, when you do this:
socket.to(roomname).emit(...)
socket.io looks up the roomname you pass in its internal data structure. If it's there, then it can get the socket from that data structure and can then send to it.
Because socket.io also automatically creates a room with the name of the socket.id that every socket is given, you can also do:
socket.to(socketID).emit(...)
And, using the same mechanism above, it will look for a room named with the socketID and because there is matching room for every socket that is connected, it will find that room and then send to the socket with that socketID.
socket.io itself does not have any notion of username. You would have to add that level of functionality yourself or get it from a cookie (if there's already a login cookie) when the socket.io connection is first established.

Socket.io client specific variable

How do I store session specific info in Socket.io?
var client={}; //is this static across all sockets (or connected clients) that are connected?
io.on('connection', function(socket){
client.connectiontime=Date.now();
});
//on another io.on('connection') for the same connected client
io.on('connection', function(socket){
store(client.connectiontime);
}
How do I use the client variable only for the operations related to the currently connected client if it is considered static?
First, each socket is given a name that can be used to refer to it, but that changes each time the same client connects so this would not be useful if it is supposed to remain after the client leaves. If your goal is to store the connection time somewhere (a database?) then you would have to get a unique identifier from the client that could be used to find them again similar to a login. You would then pass the date object into the function that handles storing that time.
You should note though, that 'connection' is only called the first time the socket connects. A connection is not the event you normally would be using for when a client does something unless they disconnects between each access of the server program.
If you are sure you want to just use the Client object, you would likely have to create a client array and use the socket id as a key to access the object later. You would then have something like
array[socket.id].connectiontime = Date.now()
var client={}; //is this static across all sockets (or connected clients) that are connected?
var clients = [];
io.on('connection', function(socket){
clients[] = {
id : socket.id
connectiontime : Date.now()
}
});
//on another io.on('connection') for the same connected client
io.on('connection', function(socket){
// Here you would search for the object by socket.id and then store
store(client.connectiontime);
}

how to get number of socket connections using socket.io

Is there a way to get the number of connections in socket.io?
I want to display a message on my site that says "x users connected right now"
Basically if I did a socket.broadcast I want to count how many connections that would go to.
You can use
io.sockets.clients().length
Basically io.sockets.clients() returns Socket instances of all clients. If you're using rooms then you should better use
io.sockets.clients('room').length
because it returns socket instances of all clients in a particular room
Using this code Server site
var noOfUser=[];
socket.on('someEventFromClient',function(data){
//User name must unique
socket.username=data.username;
noOfUser.push(data.username);
//Now you can emit no of user to client are any where
console.log('NO of user:'+noOfUser.length);
});
socket.on('disconnect',function(){
for(var i=0;i<noOfUser;i++)
{
if(noOfUser[i]==socket.username)
{
noOfUser.splice(i,1);
}
//Now you can emit no of user to client are any where
console.log('NO of user:'+noOfUser.length);
}
});
Client side:
when user connect socket server emit this event
socket.emit('someEventFromCLient',{username:'someuniqueID'});

Socket.io on socket disconnect

I have this scenario with socket.io:
A socket connects and joins a room and he is the master. Other sockets join his room. When master disconnects I want to kick all other sockets from this room.
I thought of this:
socket.on('disconnect', function(data){
// if socket's id == room he is the master and kick other sockets from this
// room and join them to a room of their own identified by their ids.
});
I want to do this without too much logic and for loops to stall the application. Is it possible to something like io.sockets.leave(socket.room)?
alessioalex's answer returns an error because it tries to call "leave" on an array of sockets. This is a working solution:
io.sockets.clients(socket.room).forEach(function(listener) {
listener.leave(socket.room);
});
I am not 100% sure, but after reading Socket.IO's documentation on github I think this should work:
io.sockets.in(socket.room).leave(socket.room);

Resources