How can i send data to u particular user using socket.io - javascript

i am building a mobile app with ionic, i am using socket.io, i want to be able to send message to a particular user with an id, and not broadcast the message to everyone, the chat application is not a chat room style kind of app but a one on one chatting app like watsapp, i searched online but what i saw was not working, here is the code for the server side
const io = require('socket.io')(server);
io.on('connection', socket => {
console.log('New user connected');
socket.on('get_all_msg', data => {
DBConn.query(`SELECT * FROM chats WHERE rec_id = ? || send_id=?`, [data.id, data.id], (error, results, fields) => {
if (error) throw error;
io.to(data.id).emit('all_msg', results)
});
})
})
the id of the user i am chatting with is the data.id, i tried using io.to(data.id).emit('all_msg', results) but the user did not receive any message, pls what am i doing that is not right
Here's the client side code
this.socket.emit('get_all_msg', {id:this.contactInfo.id})
this.service.socket.fromEvent('all_msg').subscribe((data:any) => {
console.log(data)
})
I am using ngx-socket.io in my ionic add

we need to map socket id to user id;
we can solve this using redis but simple way i did was
actually socket io itself joins the current into a room with its id(socketio) itself;
i was like, "why not join that socket into room with user_id"
backend side:
io.on('connection',socket=>{
socket.on('join-me',userid=>{
socket.join(userid);
})
})
front end side:
const socket=io(`blahblah`);
socket.on('connect',()=>{
socket.emit('join-me',current_user_id);
})
when one user emits new-message event
we can get the participent id's and can simply loop over their ids and emit an event
socket.on('message',data=>{
//do some logic let say
participents=data.participents;
parsedMessage=someLogic(data);
for(id of participents){
//here is the magic happens io.to(room_id) here room id is user id itself.
io.to(id).emit('new-message',parsedMessage);
}
})
works with one to one and group chat!

Related

Ideal way to handle multiple socket rooms?

So I am creating a chat application and I want to handle multiple chat rooms. Now I watched some tutorials and came up with a way.
const io = require("socket.io")(http);
io.on("connection", (socket) => {
socket.on("joinRoom", (roomid) => {
//Joining the room
socket.join(roomid)
//Broadcasting all previous messages
io.to(roomid).emit("messages",allPreviousMessages)
})
socket.on("chatMessage", (data) => {
//Saving msg to dB then broadcasting
io.to(roomid).emit("message",receivedMessage)
})
socket.on("disconnect",(data) => {
//updating user's lastSeen info in dB
})
})
So on my frontend when user clicks on a chatroom we call the "joinRoom" event and connect to the room and on clicking another chatroom make the same process of joining room.
Is this an ideal way for handling multiple chatrooms? If not so please let me know a better solution.
I think the best way to implement private rooms or channels or chats is this way. I have implemented an example for these three sections. Link
User token and api must be authenticated before connecting to socket.io. If this part is ok it will connect to socket.io otherwise it can't cause you to see the event that is there. Something happens by calling each of them. For example, by calling this onNotificationForVoiceCall event, the received data is first checked, then it is checked whether this user is present in the list of online users or not, and the state of the next step is checked. Whether or not this room has already been created in the database, the response of all these operations is returned to the user by socket.emit,
And I fixed some bug in project.

Socket IO and Dynamic Rooms

If anyone is experienced with Websockets / Socket IO hopefully you can point me in the right direction.
I made a Discord Clone and I'm trying to optimize it to scale better. Right now when a user sends a message I query the DB for all users part of that server, and emit a message to their specific socket. This is obviously not going to scale well as every message requires a expensive query and lookup in the client list
// Emit messages to only users part of specific server
// Will only return list of users part of server and active in last 10 minutes
sqlQuery = `SELECT userservers.user_id FROM userservers
JOIN users ON users.user_id = userservers.user_id AND users.user_last_active > (NOW() - INTERVAL 10 minute)
WHERE server_id = ${sql.escape(serverId)}`;
const users = await sql.query(sqlQuery);
action = { type: "message", payload: msg };
// Iterate over users, and find them in clients list
// Emit over socket only to that user
users.forEach((user) => {
clients.forEach((client) => {
if (client.userId === user.user_id) {
io.to(client.id).emit(user.user_id, action);
}
})
});
However using Rooms for each Sever would eliminate my need to query the DB. I understand I can do this when the socket server first starts
// Get server list from Mysql DB
servers.forEach((server) => {
socket.join(server.name);
}
However my issue becomes, when a user create a new server once the application is already running It will not update the list.
I am probably missing some concept on creating dynamic rooms.
EDIT : I am thinking the solution could be that every time a "server" is created, I send a message to the socket server so it can join that "room"
Right now when a user sends a message I query the DB for all users part of that server
I think you can submit broad cast message to all online users, so instead of forEach client => io.to(clientId) you can submit broad cast message to all connected users io.emit('some event', { for: 'everyone' });
also I'm wondering why you are creating many servers? you can divide your server into namespaces by using const namespace = io.of('/thisIsASeparateNamespace'); and also you can submit broadcast messages to all users inside this name space by namespace.emit('some event', { for: 'everyone in name space' });
So your chat structure can be like this
Server
Namespaces // for separate chat app / or like slack work spaces
Rooms // for group chatting
ClientID // for one to one

Socket.io reconnection causes new username

I am creating a chat in node.js and socket.io.
When a user opens my application, I ping the server and ask it to let the user join a specific room and set a random username (which can be edited at a later stage).
I use this
io.on('connection', (socket) => {
socket.on('join room', (roomId, callback) => {
// leave and join room
if (socket.roomId) {
socket.leave(socket.roomId);
}
socket.roomId = roomId;
socket.join(roomId);
// set username
if (!socket.username) {
socket.username = getRandomUsername();
}
});
});
It seems to work, but I have experienced situation where I have had the application running for a long time, and suddenly the user's username has changed.
I am suspecting this to occur because the user has lost connection, and socket.io have tried reconnecting. When the user has reconnected, the original socket is lost (and therefore it has no username), and a new username is assigned to the new socket, which overrides the original client socket.
Is there a problem with my code by assigning a random username to the user like this? It is somehow the same Google Docs does when the user is not signed in (they often give you an animal's name).
How can I solve the problem? I would very much like to avoid using cookies. An option could probably be to tell the client that it lost connection, and it has to reload the page, and then ask the server to get the same username.
I already save the assigned username on the client with this code:
const socket = io();
let username = null;
socket.on('connect', function() {
socket.emit('join room', roomId, function (newUsername) {
username = newUsername;
});
});
(...)

i would like to private message a user [duplicate]

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 add rooms in Node.js with Socket.io?

I have been following up many articles to learn making chat application with Node.js and Socket.io. Everything is clear and I can make an application moving messages from client to server and emitting to all etc but only one thing is not clearing and cannot figure this out.
How can I add rooms to io.sockets.manager.room?
What is the code to add rooms to sockets.manager? The most simple and thorough article I found is http://udidu.blogspot.com/2012/11/chat-evolution-nodejs-and-socketio.html but after a long struggle I still could not find where the author adds new rooms to server.
io.sockets.manager.room
returns list of rooms. Your question is not correct. You don't add rooms to io.sockets.manager.room instead you make a socket join a room and that room is added to io.sockets.manager.room.
To make a socket join a room use this:
io.sockets.on('connection', function(socket){
var room = 'Your room name';
socket.room = room;
socket.join(room);
socket.on('disconnect', function(){
socket.leave(socket.room);
});
});
There is a easier way to do I think.
io.on("connection",socket => {
socket.on("joined", (username, room) => {
server.join(room)
io.to(room).emit("joined",username")
})
})

Categories