Socket IO send to specified user ID - javascript

I want to send data to the specified user, and no one else.
currently to broadcast to everyone I do:
socket.on('newChatMessage', function (message) {
socket.broadcast.emit('newChatMessage_response', { data: message});
});
now what I want to do is simply something like:
socket.on('newChatMessage', function (message) {
socket.to(5).send('newChatMessage_response', { data: message});
});
to(5) would be the user with the ID of 5.

I think the missing piece for you is inside this function: io.sockets.on('connection', function(socket) { ... });- That function executes every time there is a connection event. And every time that event fires, the 'socket' argument references a brand new socket object, representing the newly connected user. You then need to store that socket object somewhere in a way that you can look it up later, to call either the send or emit method on it, if you need to send messages that will be seen by only that socket.
Here's a quick example that should get you started. (Note: I haven't tested this, nor do I recommend that it's the best way to do what you're trying to do. I just wrote it up in the answer editor to give you an idea of how you could do what you're looking to do)
var allSockets = [];
io.sockets.on('connection', function(socket) {
var userId = allSockets.push(socket);
socket.on('newChatMessage', function(message) {
socket.broadcast.emit('newChatMessage_response', {data: message});
});
socket.on('privateChatMessage', function(message, toId) {
allSockets[toId-1].emit('newPrivateMessage_response', {data: message});
});
socket.broadcast.emit('newUserArrival', 'New user arrived with id of: ' + userId);
});
Edit: If by id you're referring to the id value that socket.io assigns, not a value that you've assigned, you can get a socket with a specific id value using var socket = io.sockets.sockets['1981672396123987']; (above syntax tested using socket.io v0.7.9)

It's hard to say exactly how to do this without seeing your full code, but it sounds like you want to call the emit method on the individual socket you're trying to send to. If this is different from the socket making the connection (ie., a private chat partner) then you'll need some other way of storing and retrieving the correct socket you're trying to communicate with.
var sck = someFunctionToGetAppropriateSocketObject();
sck.emit('newChatMessage_response', { data: message});
see http://socket.io/#how-to-use and https://github.com/learnboost/socket.io

Related

Socket.io emitting to socket.id when stored in variable not working

as given in Sending message to a specific ID in Socket.IO 1.0, it is possible to emit to a specific client id by using
io.to(socketid).emit('message', 'for your eyes only');
In my node.js application, I am attempting to do the same thing. Basically, when the user submits another's socket.id, the node.js backend is to send the data given to that specific socket id. While the front-end submits the request correctly to the backend, when I attempt to send the data to the id, it does not go through. The "broken" part of the code looks like this:
app.post('/send', function (req, res) {
var post_body = req.body;
var id = (JSON.stringify(post_body.id)).split('"')[1].split('"')[0];
var payload = JSON.stringify(post_body.payload);
var user = JSON.stringify(post_body.user);
console.log(id);
console.log(payload);
console.log(user);
io.to(id).emit('testerEvent', { description: 'A custom event named testerEvent!'});
res.status(200);
});
which is responding to the posted data (data is posted correctly). The client listens for the event 'testerEvent' as follows:
socket.on('testerEvent', function(data){document.write(data.description)});
When the event testerEvent is fired with just io.emit, and not io.to(id).emit, it works fine.
I would appreciate any help on this, as I am just beginning to learn node and socket.io
io.to(id) will send a message to clients that joined a room, so if you have not joined any clients to a room you won't receive the message on a client. To resolve the problem you may try to do client.join(id) when you receive a client socket from Socket.io.

Emit event for particular user if login functionality in application in Socket.io with Node.js

I have used methods socket.on and io.emit, And i got response to all users. But, i want to get response for particular user.
But my application contains login functionality and i followed this post on stackoverflow, and they are saying we need unique userId and socketId in an object for a particular user to emit an event for a particular user.
But i am getting the userId after login, But we want it when user connect to app.
So can anyone please help me with the same?
In your node.js, create a global array 'aryUser', each element contains the socketid and loginid.
node.js onConnect (new connection), add a new element to the array with the socketid and set loginid = empty.
after the user login, emit an event from client to the server, e.g:
socket.emit('userloginok', loginid)
in node.js, define a function:
socket.on('userloginok', loginid)
and in this function, search the aryUser with the socketid and replace the empty loginid inside the array element with the parm loginid.
in node.js, define the function:
socket.on('disconnect')
and in this function, search the aryUser, use aryUser.splice(i,1) to remove the user just disconnected.
that means, aryUser contains all users connected, some of them logined, some of them not logined. And you can use the socketid of the array to send message to particular user, and/or all users.
Example Source Code:
server.js
http://www.zephan.top/server.js
server.html
http://www.zephan.top/server.html.txt
rename server.html.txt to server.html, put server.html and server.js in the same directory, and run:
node server.js
Yes, you definitely need socketId in order to send and receive messages between two specific users.
UserId is required just to keep track of socketId associated with the particular user or you can manage it with some other way as well that's up to you.
As per your question, you have userId of the user and you need socketId of that user! So, in this case, you can pass userId when that particular connects to a socket server from the client side as shown in below snippet,
const socket = io(this.SOCKET_SERVER_BASE_URL, { query: `userId=${userId}` });
And you can read this user on nodejs server like this,
const userId= socket.request._query['userId'],
const socketId= socket.id
Now store this socketId in somewhere, for example, Redis or some sort of caching mechanism again up to you, just make sure fetching and retrieval should be fast.
Now while sending a message just pull the socketId from your cache and emit the message on that socketId by using below code,
io.to(socket.id).emit(`message-response`, {
message: 'hello'
});
I have written a complete blog post on this topic on both Angular and AngularJs, you can refer those as well.
Edit 1:
Part 1 =>
When your user completes the login request, then make the connection to the socket server.
Assuming you are using React Or Angular After a successful login you will redirect your user to home component(page). On the Home component(page) make the socket server connect by passing the userId just like this,
const socket = io(SOCKET_SERVER_BASE_URL, { query: `userId=${userId}` });
P.S. you can get userID from URL or maybe using a cookie that is up to you.
Once you receive this socket connection request on the server, then you can read the userID query and you can get socketId associated with it and store it in cache like this,
io.use( async (socket, next) => {
try {
await addSocketIdInCache({
userId: socket.request._query['userId'],
socketId: socket.id
});
next();
} catch (error) {
// Error
console.error(error);
}
});
Part 2 =>
Now, let's say you have a list of the users on the client side, and you want to send a message to particular users.
socket.emit(`message`, {
message: 'hello',
userId: userId
});
On the server side, fetch the socketId from the cache using UserId. Once you get the socketId from cache send a specific message like this,
io.to(socketId).emit(`message-response`, {
message: 'hello'
});
Hope this helps.

Socket.io, message to yourself

Socket.io doesn't display messages send on yourself ip.
For example
var id = 333;
socket.broadcast.to(id).emit('user', user);
It working good, but message is only in client #333, but user than sent message, do not have a copy in the message client.
I wanted to solve in this way, but it does not work
socket.broadcast.to(socket.id).emit('user', user);
Why?
Without more code its hard to say what you want but one thing is certain in order to send a message to a single user you must use that socket object and use socket.emit
As far as i know broadcast is only used to tell everyone except for yourself.
What i usually do when it comes to keeping track of users is i have the following:
var userList = [];
io.on('connection', function (socket) {
socket.on('userData', function (userDetails) {
userDetails.socket = socket;
userList[userDetails.id] = userDetails
});
});
Basicly when a user connects to my socket and the page for the user is fully loaded it sends its id (or a token if you wish) i then map the user's socket into the list so i can quickly pick it up again if i wish to send to that user.
An example could be:
user.id = 33 connects to our server
Once loaded the users emits to our server userData function
The socket is then taken and put into the list at row 33
When we need to we can this use the following code to get the users socket:
socket = userList[33];
or if we have the object:
socket = userList[user.id];
I hope this helps you.
For this, you can use socket.emit('message').
socket.emit: Emit for only one socket.
Hope this will help you. You can also check out this link: socket.io send packet to sender only

get tab's socket instance on server

I have to get socket instance in my ajax request on server in node.js module. Here is my code.
app.js
io.set('authorization', function (handshake, callback) {
if (handshake.headers.cookie) {
cookieParser(handshake, null, function(err) {
handshake.sessionID = handshake.signedCookies['express.sid'];
});
} else { return callback('No cookie transmitted.', false); }
});
io.sockets.on('connection', function(socket) {
var session = socket.handshake.session;
var userid = session.userid;
socket.join("room");
//make user offline
socket.on('disconnect', function() {
//my code goes here...
//make user offline
})
});
Now in one of my ajax request, I want socket instance
app.post('/logout', function (req, res) {
//here i want socket instance, so I can emit message to all socket, accept this.
});
As I know, each tab creates it's own new socket connection, but session is unique between all tabs of browser. So, How Do I store socket for each tab on server side, where I can find easily socket instance, and then broadcast message to all sockets, excluding that socket which is creating events. (means user's active tab's socket connection)
any guess.
thanks
In my app, I can do what you say because i use namespace and room and so in a room i can find every socket of someone.
io.of('/user').clients(idRoom);
So that i can remove every socket of the user. But if you cannot use this, i think in your app you will have to implement outside socket.io a class for someone (using session as a way to see if it's already have a socket open or if you have to create a new instance). And in this class, have a socket table so that you will be able to handle socket of someone.
In my case, i do the same except that i use the room of socket.io to do that.
And to broadcast to every socket, it depends what is your app. If your app send to anyone in the same namespace, it doesn't change anything because the socket of the same session will also receive the message. But if not, you will have to implement a function to emit to every socket of the table i suggested above.
In my case i use the 'exclude' to ensure the current socket doesn't receive the message but usually you can use broadcast.
io.of('/user').in(this.id).except(socket.id).emit('msg', { text: text,type:person});
To conclude, socket.io will not help you to handle session and several socket for one user/session but you can manage to deal with it using room feature (in my case it was the best way), or implement a user class where you will manage a table of your session sockets.

Socket.io with Cluster: iterating over all open connections

I'm running Socket.io multi-threaded with the native cluster functionality provided by Node.js v0.6.0 and later (with RedisStore).
For every new change in state, the server iterates over each connection and sends a message if appropriate. Note: this isn't "broadcasting" to all connections, it's comparing server data with data the client sent on connection to decide whether to send the server data to that particular client. Consider this code sample:
io.sockets.clients().forEach(function (socket) {
socket.get('subscription', function (err, message) {
if(message.someProperty === someServerData) {
socket.emit('position', someServerData);
}
});
This worked fine when there was only one process, but now, the client receives a message for each Node process (ie. if there are 8 Node process running, all clients receive the messages 8 times).
I understand why the issue arises, but I'm not sure of a fix. How can I assign a 1-to-1 relation from one process to only on client. Perhaps something using NODE_WORKER_ID of Cluster?
This previous SO question seems somewhat related, although I'm not sure it's helpful.
This seems like a pretty common request. Surely, I must be missing something?
So if I get this straight you need to emit custom events from the server. You can do that by creating your own custom EventEmitter and triggering events on that emitter, for example:
var io = require('socket.io').listen(80);
events = require('events'),
customEventEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'positionUpdate' event
// which will be triggered by the server later on
eventEmitter.on('positionUpdate', function (data) {
// here you have a function that checks if a condition between
// the socket connected and your data set as a param is met
if (condition(data,socket)) {
// send a message to each connected socket
// if the condition is met
socket.emit('the new position is...');
}
});
});
// sometime in the future the server will emit one or more positionUpdate events
customEventEmitter.emit('positionUpdate', data);
Another solution would be to have those users join the 'AWE150', so only they will receive updates for 'AWE150', like so:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
if (client_is_interested_in_AWE) { socket.join('AWE150'); }
io.sockets.in('AWE150').emit('new position here');
});
Resources:
http://spiritconsulting.com.ar/fedex/2010/11/events-with-jquery-nodejs-and-socket-io/

Categories

Resources