Socket.io - Emit broadcast message except my sockets id - node.js

I'm building an application in real time with socket.io
Each time the user enters the application creates a socket ID.
So if I joining the application in several browser tabs generates me a socket id for each tab.
I generate a room for specific users and included my sockets id,
but I need to emit broadcast message except to my sockets id.
This code don't work for me because emit broadcast message but sends to my other id sockets
socket.broadcast.to("room").emit('message', "somethings")
Any ideas?

Assuming you are using some application framework like express along side socket.io, you can use the valid session id obtained from Express.js for maping the socketIDs generated from the same session.
Other than maping the socketIDs to the sessionID, I dont think there is a way to obtain all the socketIDs generated across tabs as the information on other tabs wont be accessible in the current tab context.
Below are few existing questions discussing this same case:
manage-multiple-tabs-but-same-user-in-socket-io
socket-io-and-session

Related

How to structure private chat messenger using socket.io and node

I'm working on a private chat messenger application using react-native node and socket.io and need to set up the structure of the project and the data. the internet seems to be overloaded with ton of different answers and I was hoping to get some answers about the problems I have with these solutions
So as far as I understand from the official socket.io documentation
https://socket.io/docs/rooms-and-namespaces/#Namespaces
namespaces were meant to "separate concerns within your application by introducing separation between communication channels" which sounds exactly like what I need for creating a separation between different conversation.
and rooms "Within each namespace, you can also define arbitrary channels that sockets can join and leave."
Here is the data structure I had in mind:
Conversations (namespaces) table -
id, namespace, user1, user2
Messages table-
conversationId, content, from(user1/2)
Here is the general flow I had in mind :
Step 1 -
User connect the main namespace ('/')
Step 2 -
The server returns a list of all user's conversations (namespaces) from the conversation table in the database
Step 3 -
Connect the user to (all?) his namespaces (or should I only connect him to the conversation he enters?)
Step 4 -
Join to default 'chat' room under each namespace (is this really necessary in a private chat application ? I know on slack for example it make sense because we speak to the same group of people under different channels, but is there any other advantage for room that I'm missing? and if it does necessary should the user join all the rooms belongs to him when the applications first fire or should I only join him into the room he enters?)
Step 5 -
When a user enters specific conversations he get all the chat history under this conversation (from Messages table in the database)
Step 6 -
When a new conversation is added we add a record to the conversation table (and we emit 'newConversation' event to the entire namespace/room that include just the sender for now (how do I make sure to notify the receiver about the new namespace related to him should I emit the event to the main name space and validate the access right on connection to namespace attempt or should I use a solution like #)) perhaps this is out of the socket.io scope and should be left to the server to deal with ?
Step 7 -
When a new message is sent we add it to the messages table and emit 'newMessage' event to the entire namespace/room
# on many places I saw some versions of the following solution:
How to send a message to a particular client with socket.io
which basically suggest storing a dictionary relating between each user and his socket id, what I don't understand is, every time a user refresh/login/logout he receive a new socket id and all the events we emitted to his previous socket id will now be lost
My expected result is a chat like whatsapp or facebook messenger (but with private conversations only) where you get notified in messages in other conversation even when you are on the home page and not inside a specific conversation

Using socket.io-redis & multiple servers/processes. How do I send a message to a specific socket ID with a callback?

I have multiple processes & servers, and am using socket.io-redis with session affinity (on Heroku).
When a client connects, I store a map of the client's user ID to the client's socket ID in Redis. Upon disconnecting, I delete the client's user ID from Redis.
I would like to be able to push a message to a client by looking up the client's socket ID, then sending a message to the specific socket ID.
One way to do this is io.to(socketId).emit(...). However, this does not allow me to send a callback with the message, which I would really like because I want to have confirmation of message receipt.
Another way I have found is io.connected[socketId].emit(...). The problem with this is that it does not scale to multiple servers, since the io.connected object may not necessarily be the same on every server since it only records sockets that the server itself is connected to. This solution does allow callbacks, however.
Is there a way to solve this so I can emit messages to a specific socket ID from any server or process, and also send a callback with the message?

How to send real time notification to single user using node.js and PHP

I am trying to integrate real time notifications with Node and socket.io in a Symfony Application. I have read a lot of information about this topic and have a working Node application.
nodeClient.js
var socket = io.connect( 'http://192.168.15.106:8080' );
$('a.sendSmile').click(function(){
socket.emit( 'message', { name: 'something' } );
});
socket.on('message', function(data){
console.log(data.name);
});
The problem now is with the above which is working perfectly I am able to send real time notification to all the users at once. But what's the best way to target a single user?
For example a user can send a smile to another user so only the second user should receive the notification and not all the users.
Should I make multiple listeners for node? or any other method to do this?
You need some way of identifying which socket that connected to your server is the one you want to send data to and then you can send to just that socket. You can keep track of user names when users connect or if you have some auth system, you can keep track of which socket belongs to which authenticated user.
Your server holds a list of connected sockets. Each connected one at a time and triggered a connection event on your server when they connected. Your application needs to create a way of knowing which of those connected sockets you want to send the data to. This is not something you've described anything about how you want that to work so we can't really help more specifically.
You can dispatch a notification to single user if you can discriminate that user. For example you can get a user_id on client connection to your nodejs server (the user_id is send from client, inside message) and save it in a key-value store (like Redis, memcache, ...). In this way you can correctly dispatch the notification, arrived from the server (like Symfony2 application), to right user.
I suggest you use Redis, both as a key-value store and for its implementation pattern of the publish/subscribe usable as a channel of communication between the server and the application of realtime.

Two instances of one socket.io connection

In our app, every time a user signs in a new connection in socket.io is created. So if a user signs in simultaneously on more devices, they behave as separate connections. Instead of creating a new connection every time, I'd like to check whether the user is already connected to socket.io and if he is, I'd like to connect him to already established connection. How can this be done?
From the socket.io perspective, those ARE two connections. But if it was my app, I would do something like this:
add a user identifier (userid, username, something you identify users by) to both the users' socket.io connection (so, each time you send a message to the client, you also pass this id)
pass this id also to the client-side code on init.
So now the socket on the server side has its' socket.io id, but also your user id. Anyway, to proceed:
send this user-id to the client in it's javascript files.
on the client-side code, make a small adjustment to socket.io handler - for each received message (say, broadcast), you can now check if it's your current user-id and instead of saying 'User #351 says Hi' you can say 'You said Hi on another device' or something like that.
Of course, I'm not socket.io expert, there's could already exist a framework or lib addressing this.

How do I restrict access to a broadcast message in NodeJS?

I understand routing (I think), but what's to stop User A from looking at User B's client-side source to discover the socket.io URL specific to each user and then build their own script to start listening for broadcast messages on that particular channel?
You would need to use something to determine who the client is. Once you do that, you could for example use the rooms feature, and only broadcast to the specific room where you put all your authorized users.
To identify the client, you could pass in cookies from the browser in a socket.io request, and compare that to any session data you have stored in Express/Connect/Whatever.

Resources