socket-io-changes-socket-id-repeatedly part 2 - node.js

Following on the question asked by me:
socket io changes socket.id repeatedly
Registering only happens when the client comes on the chatpage:
On the client:
socketConnect: function() {
socket = io.connect('https://socket.mydomain.nl');
socket.on('connect', function() {
socket.emit('register', userID, 'Lobby');
});
};
Server
var UserSockIdStorage = {},
Allsocketids = [];
//Clients connect and register here.
io.sockets.on('connection', function(socket) {
socket.on("register", function(userID, currentchannel, userinfostr) {
console.log('USER WITH ID ' + userID + ' REGISTERS WITH THE SOCKETIDOF: ' + socket.id);
UserSockIdStorage[userID] = socket.id; //userid is associated with the socket ID.
socket.room = currentchannel;
socket.join(currentchannel);
});
As you can see i store the username in an array with the socket ID as its value.
When a message is to be send the username is looked up to retrieve the socket ID to send the message to.
Now come the part that i don't understand:
Clients keep reconnecting (Not registering so the socket id is not saved in the array!!) from time to time and i can see that they get another socket ID.
My guess would then be, that when i look up by username (Array UserSockIdStorage) a socket ID to send a message to, and the owner of that ID made several reconnects thus acquiring a new socket ID over and over again,
that a message send to the lookedUp socket ID wouldn't go anywhere since the client obtained several new socket ID's in the meanwhile.
But from what i'm observing the message is routed to the correct client so the first socket ID is still it's socket ID?!
Are those ID's cached or somewhat?

Related

node.js socket.io app - How to kick someone from chat room?

So I have chat app in which only two users can be in a room at a time.
Please note that clientInfo is a global variable and anytime a new user joins a room, an object variable is passed to the server with username and room name. Then this code is executed
socket.on('joinRoom', function(userDetails){
clientInfo[socket.id] = userDetails; //variable contains name and room joined.
socket.join(userDetails.room);
}
I added a feature where a user can type 'kick' as the chat message which will call this function:
function kickUser(socket){
socket.leave(clientInfo[socket.id].room);
delete clientInfo[socket.id];
}
the above code works fine but how can i change the function to kick the other user in the room? I tried the code below but I still ended up kicking myself out. I take it that socket.leave() doesn't care about the socket id but it just uses the room name and the person who called the function.
function kickUser(socket){
var info = clientInfo[socket.id];
if (typeof info == 'undefined'){
return;
}
Object.keys(clientInfo).forEach(function(socketId){
if(info.room == clientInfo[socketId].room) {
if (info.name != clientInfo[socketId].name){
socket.leave(clientInfo[socketId].room);
delete clientInfo[socketId];
}
}
});
}
Try implement next idea
In socket.on('connection', function(socket){ ... }); you must identify user name and room for this connection/socket: client can send username/room on connection itself
socket.on('connect', function {
socket.send(JSON.stringify{do: "introduce", name: "User1", room: "dasRoom"})
})
or server can read it in client cookie. Also you can check here user count in room. This info can be stored in global vars.
User can do kick by send specified message by socket, e.g. {do: "kick
, user: "User1"}, or request url. e.g. /kick/User1.
Function Kick must implement logic to find user by name, send goodbay message to victim and disconnect socket. Also server must send User1 leave room to alive user by socket.

Socket io. Disable automatical joining a room identified by socket's id

In docs it is said: "Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id. For your convenience, each socket automatically joins a room identified by this id."
I am wondering if there is an option to disable such feature.
My solution was:
io.on('connection', function (socket) {
leaveDefRoom(socket);
[...]
}
function leaveDefRoom(socket){
var room = socket.adapter.rooms;
for (var key in room){
if (key.charAt(0) == '/') {
socket.leave(key);
return;
}
}
}
In socket.io. Every time you emit event. socket.io send the event to the client in this room. If you remove user from the room, you cannot send this user messages. Even broadcast will not work.
Anyway, if you really want, you can leave this room, like any other room:
You can change socket.js file and disable this option:
https://github.com/socketio/socket.io/blob/master/lib/socket.js#L289
Socket.prototype.onconnect = function(){
debug('socket connected - writing packet');
this.nsp.connected[this.id] = this;
// You have to remove this line below:
this.join(this.id);
this.packet({ type: parser.CONNECT });
};

Socket - send message to user by ID

I'm using Node.js with ws(a socket library) and I'm having a little trouble with finding the socket of a specific user.
when the user connects to my socket server, I'm supposed to keep his socket objct in a big massive object by his userID or socketID like this:
var bigMassiveObject = {};
ws.on('connection', function(socket){
var userID //somehow get the userID
bigMassiveObject[userID] = socket;
// to find the socket
socket = bigMassiveObject[userID];
socket.send("hi");
})
so that later I can send him message by that ID, but isn't it better to just keep his socketID? this way we are not storing all the socket, but only the ID and then somehow(which I don;t know) send him message by that ID
this is what i'm looking for:
var smallObject = {};
ws.on('connection', function(socket){
var userID //somehow get the userID
smallObject[userID] = socketID;
// to find the socket
var socket = generateSocketObjectBySocketID(socketID);
socket.send("tada!");
})
so the question is, is there anyway to generate the socket, by the socketID(or useID)? so that we wouldn't be storing all these big socket objects in memory and there wouldn't be any memory leakage too :)
Simply,
This is what you need :
io.to(socket.id).emit("event", data);
whenever a user joined to the server,socket details will be generated including ID.This is the ID really helps to send a message to particular people.
first we need to store all the socket.ids in array,
var people={};
people[name] = socket.id;
here name is the reciever name. Example:
people["trojan"]=2387423cjhgfwerwer23;
So, now we can get that socket.id with the reciever name whenever we are sending message:
for this we need to know the recievername.You need to emit reciever name to the server.
final thing is:
socket.on('chat message', function(data){
io.to(people[data.reciever]).emit('chat message', data.msg);
});
Hope this works well for you.!!Good Luck

socket.io private message

I've beeen scouring the Net with no luck. I'm trying to figure out how to send a private message from one user to another. There are lots of snippets, but I'm not sure about the client/server interaction. If I have the ID of the socket I want to send to, how do I send it to the server, and how do I ensure the server only sends the message to that one receiver socket?
Is there a tutorial or walkthrough that anyone knows of?
No tutorial needed. The Socket.IO FAQ is pretty straightforward on this one:
socket.emit('news', { hello: 'world' });
EDIT: Folks are linking to this question when asking about how to get that socket object later. There is no need to. When a new client connects, save a reference to that socket on whatever object you're keeping your user information on. My comment from below:
In the top of your script somewhere, setup an object to hold your users' information.
var connectedUsers = {};
In your .on('connection') function, add that socket to your new object. connectedUsers[USER_NAME_HERE] = socket; Then you can easily retrieve it later. connectedUsers[USER_NAME_HERE].emit('something', 'something');
Here's a code snippet that should help:
Client-side (sending message)
socket.emit("private", { msg: chatMsg.val(), to: selected.text() });
where to refers to the id to send a private message to and msg is the content.
Client-side (receiving message)
socket.on("private", function(data) {
chatLog.append('<li class="private"><em><strong>'+ data.from +' -> '+ data.to +'</strong>: '+ data.msg +'</em></li>');
});
where chatLog is a div displaying the chat messages.
Server-side
client.on("private", function(data) {
io.sockets.sockets[data.to].emit("private", { from: client.id, to: data.to, msg: data.msg });
client.emit("private", { from: client.id, to: data.to, msg: data.msg });
});
Although we have nice answers here. However, I couldn't grasp the whole client server unique user identification pretty fast, so I'm posting this simple steps in order to help whoever is struggling as i did.....
At the client side, Get the user's ID, in my case I'm getting the username...
Client side user registration
//Connect socket.io
var systemUrl = 'http://localhost:4000';
var socket = io.connect(systemUrl);
//Collect User identity from the client side
var username = prompt('Enter your Username');
socket.emit('register',username);
The Listen to register on the server side to register user's socket to connected socket
Serve side code User registration
/*Craete an empty object to collect connected users*/
var connectedUsers = {};
io.on('connection',function(socket){
/*Register connected user*/
socket.on('register',function(username){
socket.username = username;
connectedUsers[username] = socket;
});
});
Send Message from the client side
$(document).on('click','.username',function(){
var username = $(this).text(),
message = prompt("type your message");
socket.emit('private_chat',{
to : username,
message : message
});
});
Receive message on server and emit it to private user
/*Private chat*/
socket.on('private_chat',function(data){
const to = data.to,
message = data.message;
if(connectedUsers.hasOwnProperty(to)){
connectedUsers[to].emit('private_chat',{
//The sender's username
username : socket.username,
//Message sent to receiver
message : message
});
}
});
Receive message on client and display it
/*Received private messages*/
socket.on('private_chat',function(data){
var username = data.username;
var message = data.message;
alert(username+': '+message);
});
This is not the best, however you can start from here....
The easiest way I can think of is to have an hash of all the users on using their id or name as the key and have their socket as part of the value then when you want to send a message to just them you pull that socket and emit on it... something like this:
users[toUser].emit('msg',"Hello, "+toUser+"!");
if you have a web site that has register users with uid then you can create a room for each user and name the room by uid of the user.
first connect client to the server using :
var socket = io('server_url');
on the server side create an event for detecting client connection:
io.on('connection', function (socket) {}
then you can emit to client inside it using socket.emit(); and ask uid of current user.
on the client side create an event for this request and then send uid of the user to server.
now on server side join the connected socket to room using :
socket.join(uid);
console.log('user ' + socket.user + ' connected \n');
now you can send private message to a user using following line:
io.to(uid).emit();
if you use the code above, it doesn't matter how many tab user has already open from your web site . each tab will connect to the same room.
in socket.io 1.0 use
io.sockets.connected[<socketid>]
you can store just socket id. like so:
var users = {};
users[USER_NAME] = socket.id;
then:
io.sockets.connected[users[USER_NAME]]
.emit('private', {
msg:'private message for user with name '+ USER_NAME
});
You can create an unique room for messaging between USER_A and USER_B and both users must join to this room. You may use an UUID as a ROOM_ID (the 'socketId' in the following example).
io.on('connection', socket => {
socket.on('message', message => {
socket.to(message.socketId).emit('message', message);
});
socket.on('join', socketId => {
socket.join(socketId);
});
});
See Joining Rooms and Emit Cheatsheet
The way I got it to work is by introducing one more event "registered user". This basically triggers on the client side as soon as there is a registered user and then emits this even and passes "currentUser._id"
Client Side:
var socket = io();
<% if (currentUser) { %>
socket.emit('registered user', "<%= currentUser._id %>");
<% } %>
Server Side: Once the "registered user" even triggers, it joins the current user socket to the new room with the name which is that user id. So basically each registered user will be in a room which is his/her uid.
socket.on('registered user', function (uid) {
socket.join(uid)
});
Server Side: One there is a message sent, I pass the id of the user the message is sent to in the msg object and then emit to that specific room.
// Private chat
socket.on('chat message', function (msg) {
const uidTo = msg.uidTo
socket.in(uidTo).emit('chat message', msg )
}); `
});

How to handle user and socket pairs with node.js + redis

Straight to the point:
I am using node.js, socket.io and redis for a private chat system.
On connect user passes his website id (userID) to node.js server. He may have multiple connections so I have to pair socketID (of each connection) and userID somehow. I has thinking about using redis to store userID->sessionID pairs. However, when user disconnects I need to remove that pair from redis.. but I have only socketID not userID so I can't select by that key..
Now, am I approaching this the wrong way or should I store both userID->socketID and socketID->userID pairs? Maybe someone could offer more elegant solution?
A more elegant solution would be to make each socket connect to the channel userID, for example:
io.sockets.on('connection', function (socket) {
socket.join(userID);
});
// when you want somebody to send a message to userID you can do:
io.sockets.in(userID).emit(message);
There are two things you need to take care of here:
Make sure that only userID can connect to his channel, thus verify the session ( read more here: http://www.danielbaulig.de/socket-ioexpress/ )
On connection increase the value for userID in redis (so that you know a new connection for that user is listening) and on disconnect decrease the userID value (so that you know the number of connections still listening). If the value is 0 then you emit a message to the chat stating that userID has left (since the number of connections listening to the userID channel is 0).
When other users will want to send a message to userID, they don't need to connect to the userID channel, they can send a message to the chat channel and pass userID as a property. For example:
var chat = io
.of('/chat')
.on('connection', function (socket) {
// connected to public chat
})
.on('message', function (data) {
if (data.userID && data.message) {
io.sockets.in(userID).emit('UserX: ' + data.message);
}
});

Resources