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

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.

Related

get previous data of socket(connected user) after refresh or disconnect using socket.io and node.js

Hi i am mew to socket and node.js and developing a game application in which two users (separate browsers) plays game.
i have used server.js for node/socket and cilent.js from where user events are handled.
suppose both users are connected and playing game , if one user get disconnected or refresh browser then i am not getting its previous data like username etc. I tried to get socket id which is disconnected in
socket.on('disconnect', function()
{///timer used here in which i can get socket id of disconnected but what next
});
but next what to do, how would i know that after refersh/disconnect
same user get connected and how to get its previous data like username?
In order to keep track of disconnected users you have to create an array which will contain usernames of users which are disconnected from room, To implement this try below code,
socket.on('disconnect', function()
array.push(socket.username);
});
In order to get username of client to push in array, You will have to add username when user connects to room which can be achieved by as show below,
socket.on('joinroom',function(data){
socket.username = "user1";
}
Now you have an array which has list of usernames who were disconnected, Now when user connects to room put for loop which will rotate through array and if username is found in array then you got to know that same user is connected then you can add that user to previous room.
To get previous room of user from which user was disconnected you will have to add room also in array can be done by,
var obj={username:socket.username , room:socket.room}
array.push(obj);
And when user connects to room you will have to add room also,
socket.on('joinroom',function(data){
socket.username = "user1";
socket.room = "roomname";
}
Hope this will help

How can I identify user when user reload the page

I'm creating a card game like crazy8. And I already publish prototype.
Look here http://himapoyo.com
My problem is, when I reload the page during the game, socket is disconnected and my socket.id is changed.
So server side program can't identify me. Now, server remove player from table when socket is disconnected.(because if server don't remove the player who server can't identify, game is stopped, so I program). But if I can identify user, I don't want to remove player who just reload the page from table.
QUESTION: how can I identify user when user reload the page?
I think using cookie as ID is best for this problem. Are there Other solutions?
Other options would include:
Using local storage on the client
Passing query string values in the url
Posting the user id as part as the refresh
Storing the user in a server side session
Storing user information in redis cache.
I'm sure there are many more but this should be enough
After reading your question I understand (correct me if I'm wrong) that once a user refreshes the page (reconnects his socket) the socket ID changes (obviously) and you can't identify the user.
First of all, you shouldn't keep track of user using his socket ID as the socket ID will change every time the user reconnects. You should keep track of the socket ID for communication with the user AFTER you have identified the user.
So, what I would do is make an "authenticate" event on the server side and disconnect those sockets who don't emit the "authenticate" event. This event can expect any form of credentials (JWT, username:password etc).
After the user has been authenticated, you can take that socket ID and map that to the user ID and use the socket ID for further communication.
So the server side flow will be like this:
io.on("connect", function (socket) {
socket.on("authenticate", function(data) {
// do auth and then make other events
// if auth
socket.auth = true;
socket.emit("message", "User authenticated");
});
// If socket fails to authenticate within 3 seconds after connect, disconnect it
setTimeout(function() {
if (!socket.auth) {
socket.disconnect();
}
}, 3000);
});
After going to your app, I found that there is no authentication required. This should not be the case as I can highjack any user's slot at the table by just sending his/her name.
If you are okay with that then perhaps you can just keep track of the user name and map it to socket ID on connect.

Is there an alternate way of sending a private message with Socket.io (1.0+)?

Im working on a simple session based app shared by a session code in the URL. I decided to generate and assign a shorter user friendly unique ID for each client who connects to a socket, and the client who creates a session causes a socket.io room to be created with his ID.
I didnt realize until later that the private messaging mechanism in socket.io relied on each client being assigned to a room named by their ID. This means that because my room for a session is named after the creator's socket ID, using .to() will not message that client, but rather all of the clients now assigned to that room.
I could remedy this in ways that would require some re-design, but first I wanted to ask if there is an alternate way of sending a message to a specific client via his/her ID.
/*create an array of clients, where key is the name of user and value is its unique socket id(generated by socket only, you do not have to generate it) during connection.*/
var clients = {};
clients[data.username] = {
"socket": socket.id
};
//on server side
socket.on('private-message', function(data){
io.sockets.connected[clients[data.username].socket].emit("add- message", data);
});
//on client side
socket.emit("private-message", {
"username": userName,
"content": $(this).find("textarea").val()
});
socket.on("add-message", function(data){
notifyMe(data.content,data.username);
});

attaching data to sockets

i want to have some clients connect to a room with socket.io, then store their information into an object (like a user-list)
if they leave the channel, i want that entry to be auto-deleted.
how can i hook some "outside" information to a socket? is it possible?
example:
user named "joe" connects
socket.emit('joinRoom', {username: 'joe'});
on the server, i want to do something like
socket.on('joinRoom', function(msg) {
userData.push(msg.username); // <-- how can i simplify/automatize this?
}
is there something built-in to manage users?
(the problem arises from me wanting to hook passport-user information to sockets. joe is logged in with passport, the server reqknows that. but the socket doesn't, because there is no req at all)
eventually, i want to be able to say "send a socket message to the user that is logged in as joe". if joe leaves the channel, remove him from the userlist etc
is that possible? how would you do it? is my approach wrong?
thanks
You can add properties to the socket object:
socket.on('joinRoom', function(msg) {
socket.username=msg.username;
}
If the socket you want modify is not the transmitter you can do it through
io.sockets.connected[socket.id].username=msg.username
but you will need his id.

Socket.io - Emit to array of socket id

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.

Resources