How do I get other users socket.id? - node.js

How do I get other user's socket.id?
Since socket.id is keep changing, whenever the browser refresh or disconnect then connect again.
For example this line of code will solve my problem
socket.broadcast.to(id).emit('my message', msg);
But the question is How do i get that id?
Let say Jack wants to send a message to Jonah
Jack would use the above code to send the message, but how to get Jonah's socket id?
Just for the record, I already implemented socket.io and passport library so that I could use session in socket.io , the library is call passport-socket.io. So to get the user id in socket.io would be
socket.request.user._id

What i did for this was to maintain a database model(i was using mongoose) containing userId and socketId of connected users. You could even do this with a global array. From client side on socket connect, emit an event along with userId
socket.on('connect', function() {
socket.emit('connected', userName); //userName is unique
})
On server side,
var Connect = require('mongoose').model('connect');; /* connect is mongoose model i used to store currently connected users info*/
socket.on('connected', function(user) { // add user data on connection
var c=new Connect({
socketId : socket.id,
client : user
})
c.save(function (err, data) {
if (err) console.log(err);
});
})
socket.on('disconnect', function() { //remove user data from model when a socket disconnects
Connect.findOne({socketId : socket.id}).remove().exec();
})
This way always have connected user info(currently used socketId) stored. Whenever you need to get a users current socketId fetch it as
Connect.findOne({client : userNameOfUserToFind}).exec(function(err,res) {
if(res!=null)
io.to(res.socketId).emit('my message', msg);
})
I used mongoose here but you could instead even use an array here and use filters to fetch socketId of a user from the array.

The documentation suggests that `socket.on(SOME_MESSAGE's callback is provided an id as the fist param.
http://socket.io/docs/rooms-and-namespaces/#default-room
javascript
io.on('connection', function(socket){
socket.on('say to someone', function(id, msg){
socket.broadcast.to(id).emit('my message', msg);
});
});

Related

How to send file to a particular user in nodejs

I am creating a rest api on nodejs. I have email id and user id in database. I want to share a file (present on same server) from one user to a particular user. Can anyone tell me how this can be done in a best way ?
Here is the code i have tried yet.
const server = require('./../server/server.js')
const socketIO = require('socket.io');
const io = socketIO(server);
const mongoose = require('mongoose');
const User = require('../models/user.js');
let sockets = [];
io.on('connection', socket=>{
console.log("User connected");
socket.on('online', (data)=>{
socket.name = data._id;
sockets[data._id] = socket.id;
console.log("user is online")
})
socket.on('send_file', (data)=>{
User.find({emailId: data},{emailId:0, password:0})
.exec()
.then(userid => {
if(userid.length<1){
console.log("No such user");
}
else{
console.log(userid[0].id);
socket.to(sockets[userid[0].id]).emit('hello', "HELLO");
}
})
.catch(err =>{
console.log(err);
});
});
socket.on('disconnect', ()=>{
console.log("User disconnected");
})
})
module.exports = io;
server.listen('8080', (err)=>{
if(err) throw err;
console.log("running on port 8080");
});
Assuming that you have already configured the socketio and express sever properly with he mechanism to save the file path and file name in you database.
Try something like this (with socketio)
let sockets = [];
io.on("connection", function(socket) {
socket.on("online", data => {
socket.name = data.username;
sockets[data.username] = socket.id;
});
socket.on("send_file", function(data) {
// your logic to retrieve the file path from you database in to the variable **filedata**
// let filedata = ................
socket.to(sockets[data.user]).emit("file",filedata);
});
socket.on("disconnect", reason => {
sockets.splice(sockets.findIndex(id => id === socket.id), 1);
});
});
in send_file event you will have receive the username from the sender inside the data object. The following code will be one which will help you to send file to selected user.
socket.to(sockets[data.user]).emit("file",filedata);
Replying to your 1st comment.
history.push() will not refresh the client since its a single page application.
But when you refresh(from user A side) a new socket session will be created then the other user(user B) will still be referring the old socket session(which is already being disconnected by the refresh). So to handle this use the following lines
socket.on("online", data => {
socket.name = data.username;
sockets[data.username] = socket.id;
});
where you will be keeping a pool(an array) of sockets with the usernames so when ever a user refresh their client the newly created socket will be referring to the same user. Since you will be updating the the socket.id to the same person.
For example assume that you the user who refresh the client and im the other user. so when you refresh a new socket session will be created an it will be sent to the back end along with the user name. When the data comes to the server it will get your session object from the array(sockets[data.username]) and update it with the new socketio sent from your front-end sockets[data.username] = socket.id;.
for this to happen you will have to send the user name along with the socket message. like this
socket.emit("online", {
username: "username"
});
Replying to your 2nd comment
To send data in real time the users should be online. if not you can just create an array of notifications with the following information (sender and receiver). So when the receiver logs in or clicks on the notification panel the list of shared files notification can be shown. This is just a suggestion you can come up with you own idea. Hope this helps.
In case of Non-real time data:
Server Side-:
use res.sendFile() is a way to solve this problem. In addition to file send the receiver and sender id in headers
Client Side-:
Increase the notification count if the receiver id matches the logged in user.
res.sendFile(path.join("path to file"),
{headers:{
receiverid:result[0]._id,
senderid:result[1]._id
}
});
In case of real time data:
follow the answer posted by TRomesh

socket emit to only one user

I´ve been searching for the anwser but most of them i cant quite connect with my code so im hoping to get some help.
I want to send a message for a specific user, like a chat beetween 2 people.
For example, if i choose John how can i only send a mensage to him? im having much trouble in this
app.js
io.on('connection', function (socket) {
socket.on('chat', function (data) {
console.log(data);
//Specific user
//socket.broadcast.to(socketid).emit('message', 'Hello');
});
});
I have a mongodb database so how can i specify the socketid having the user id of the select user?
The below code can be used to send message to a specific client.
Point to be noted , every client connected has a unique socket id.
Store that id in an array. You can call any user with that id.
var id=[];
io.on('connection', function (socket) {
socket.on('chat', function (data) {
console.log(data);
id.push(${socket.id});
});
});
//to send to specific user
io.to(socket#id).emit('hey!')
You must create an userbased array. Here, you can get a special socket:
var users = [];
io.on('connection', function (socket) {
users.put(socket);
socket.on('chat', function (data) {
console.log(data);
users[0].emit('chat', data);
});
});
You can use a array based or an object based (here you can store it with the username, but you must implement a procedure to set the username after connection is available) variable.

Send a message from client to server on connection node.js

I want my client-side code to send the server the user's userid when establishing the connection, then i want the server to check the database for new messages for each user that is connecting, and send the user the number of new messages it has when new messages are available.
My client-side code:
var socket = io.connect('http://localhost:8000');
socket.on('connect', function () {
socket.emit('userid', '1');
});
socket.on('new_message', function (data) {
var number_of_messages= "<p>"+data.number+"</p>";
$('#container').html(number_of_messages);
});
My server-side code:
io.sockets.on( 'userid', function (data) {
console.log('userid: '+data);
});
My problem is that the above code is not working: the userid is never received by the serverside and the on('userid') is never called.
My question is how to know which socket sent this user id and how to send to only this specific socket a certain message.
I have solved the problem by saving the clients socket and their id into a global array. this is not a good solution but it works; I know there are rooms and namespaces but I never used it..
socket.io namespaces and rooms
however,
(I used express)
client:
var socket = io.connect('http://localhost:3000',{reconnection:false});
socket.once('connect', function() {
socket.emit('join', '#{id}');
};
server:
var clients = [];
app.io.on('connection', function(socket) {
socket.on('join', function(data) {
clients.push({
ws: socket,
id: data
});
//retrive the messages from db and loop the clients array
//and socket.send(things)
}
}

Expose socket.io listeners after client action

Is there a way to set up socket.io listeners for certain clients after they execute a command? For example:
socket.on('setupServer', function (data) {
console.log("setupServer called");
// Now set up listeners
socket.on('serverAction', function (data) {
console.log('Listener for clients calling setupServer');
});
});
In the above, a client has connected and has issued a 'setupServer' command to the node.js server. The server now listens for 'serverAction' from the specific client. Other clients won't be able to use 'serverAction' without calling 'setupServer' first.
You could create a room and validate some data from user and then join those users to that room, after that emit some events to that users in that room.
Something like this.
server.js
var io = require('socket.io')(server);
io.on('connection',function(socket){
socket.emit('auth_user')
socket.on('response_from_user',function(data){
if(data.name === "Blashadow"){
//join that user to the room
socket.join('/room',function(){
//emit some custom event to users in that room
io.in('/room').emit('custom_event_room', { info: 'new used connected from room' });
});
}
});
});
client.html
var socket = io('localhost');
socket.on('auth_user', function (data) {
socket.emit('response_from_user', { name : "Blashadow" });
});
socket.on('custom_event_room',function(data){
console.log(data);
});

can i give my own id to a connected socket in nodejs

am trying to implement a multiuser communication app. I want to identify a user's socket with his id, so can i set socket's id to user' id like
socket.id=user.userId;
This may help you
io.sockets.on('connection', function (socket) {
console.log("==== socket ===");
console.log(socket.id);
socket.broadcast.emit('updatedid', socket.id);
});
you can save socket id in client side. When you want 1-1 message (private chat) use updated socket id. Some thing like this :
io.sockets.socket(id).emit('private message', msg, mysocket.id)
You can do this, but use property that doesn't clash with Node.js or any other frameworks keys
socket.myappsuperuserid = user.userId;
Here
client side
var socket = io.connect();
socket.on('connect', function () {
console.log("client connection done.....");
socket.emit('setUserId','random value');
});
On server side
io.sockets.on('connection', function (socket) {
socket.on('setUserId',function(uId){
socket.userId = uId;
});
});
This may help...
In socket.io when a user connects, socket.io will generate a unique socket.id which basically is a random unique unguessable id. What i'd do is after i connect i call socket.join('userId'). basically here i assign a room to this socket with my userId. Then whenever i want to send something to this user, i'd do like this io.to(userId).emit('my message', 'hey there?').
Hope this help.

Resources