Sending data only to chosen users using Socket.io-node - javascript

Is it possible to send data using socket.io-node just to chosen group of users? For example, how could I implement chat with different rooms? I dont want .broadcast() to send data to all logged in users.

Normally you should have for each room a list of connected user and those user all have a client object that you should have stored somewhere. So when you want to send a message to a specific room, you just have to iterate over the connected user of that room and access their client object and send the data.
In short, it is possible you just have to send your data to each of the users in the group one-by-one.

socket.io has a grouping functionality built in
On the socket object for a single connection, like you get passed when a new user connects, you can call .join('roomName') where roomName is any string you want to use to identify the "room", you could use a room name like "profile/14" to create a channel for updates to user #14's profile.
Then on the main io object do something like:
io.sockets.in('profile/14').emit('newComment', {message:'hello'});
The message will go out to all connections that have .join()'d the given room.
Typically I'll have my client emit a "hello" event onConnect that identifies what content the client is interested in subscribing to, and then on the server side my handler for the "hello" event handles .join()'ing the client into whatever rooms are needed

Related

Display channel name in featherjs chat client

I am following this repo to build a chat application.
I am trying to show the channel name (the default room which users are logged into) in the chat client.
Is there a way to access channel info from
const client = feathers();
in the file
No, I do not believe so. Channels are a construct on the server side built on top of sockets. Each client are a socket receiving and sending data to the server. On the server sockets/clients can be grouped together into channels, so that you can easily broadcast to many clients, for example:
app.channel('authenticated').send({
warning: "Perimeter has been breached"
});
From what I understand you are trying to create a chat with multiple rooms a.k.a channels. In order to do that you need first to implement the ability to join a specific channel first, this can be done by creating multiple channels on the server, take a look here: https://docs.feathersjs.com/api/channels.html#example
in your src/channels.js:
const { user } = connection;
if (user.room == 'yoyo') {
app.channel('yoyo').join(connection);
}
Then I would recommend to store the room in the user object.
On the client side, when user sign up you could for example do something like this (app.js, line 19):
await client.service('users').create(Object.assign({ room: 'yoyo' }, credentials));
You could get which room to join from the signup form or perhaps from the path.

Pusher with multi-database companies

I'm trying to figure out what's the best approach to use Pusher in my application.
My app consists in a normal website where users log in
Each user is connected to a company
Each company has its own database
So, I need my app to allow the send of regular messages and notifications (like popups) to people that only belong to the company signed for.
Doubts/problems:
If I create a channel called notifications and send events to it, all users (no matter what company) will receive it
If I set up some sort of token associated to the company won't work because some notifications/messages should only be sent to a restrict users
In my previous project I associated a token to the company because there was no activity between users only a "show-off" of what PHP was doing (within a loop) in each company, something like:
PHP:
$this->pusher->trigger($company_pusher_token, 'feedback', $data);
JS:
var token = $('#company_pusher_token').val();
var channel = pusher.subscribe(token);
channel.bind('feedback', function(data)
{
alert('working..');
});
So, how should I proceed to accomplish what I'm looking for?
It looks like you are going in the right direction.
The channel name would always start with the company unique prefix. If only a subset of users of that company should be notified then combine the prefix with the group ID.
Channels:
"notifications": send to all companies, all clients
"<company-token>-notifications": send to all clients from a given company
"<company-token>-<group-id>-notifications": send to all clients from a group within a given company
By the way if you want to make sure your customers can't bind to another company's channel make sure either the company token is not guessable, or use the "private-" prefix to let you control the authorization on the subscription of channels.

Socket.IO emit data into a room to myself

I'm building a chat application in which I want to load on start the last messages between 2 users.
Here's what I do on the frontend so load the old messageList from the database:
socket.emit('get messageList', data);
on the backend side I load the messages into messages and try to emit them back. I dont want to broadcast.emit since I want to load the data in my session, not in the chat partners.
socket.in(roomId).emit('send messageList', messages);
When I execute this code the messageList of the chat partner gets refreshed. Basically it has the same effect as
socket.in(roomId).broadcast.emit('send messageList', messages);
Before I implemented the rooms a normal
socket.emit('send messageList', messages);
would update my list just as I'd expected. But since I use the code with rooms it doesn't work anymore.
My questions:
Why is that?
Is it possible to send back data from the backend to the client with socket.io?
Or am I doing something completely wrong?
socket.nsp.to(room).emit('room_message','hello world')
I'll make my comment into an answer since that seems to be what will work for you.
If you're just trying to respond to the client that send you a request, you just socket.emit() back to the requesting socket. You're just trying to respond to the sender so you don't do anything differently just because there are chat rooms being used. The response goes to the socket that asked for it, regardless of chat room usage.
To send to a single client, you just send to that client's socket. You only use chat rooms to help with the sending if you want to send to all clients in that room or all clients in the room except one.

How to send old messages with Websockets

I've got a working Websockets example, where clients receive messages from the server.
I'm not sure how I should send old messages to clients when they connect.
Example:
Each client supplies their name when they connect
The server responds with "[name] just connected" (to all clients)
Any new clients would NOT get these messages
I'm wondering if there's any way clients can receive old messages (either all of them, or messages in the last 5 minutes would be acceptable).
I suspect I may have to capture this information myself, store it somewhere (like a database) and send the messages to new clients myself. Is that right, or am I missing something?
If anyone has pseudo code, or a link to an example of how others have implemented this, that would be handy.
You could do something like this:
Each message should have an id -> muid (Message Unique ID)
Each time a client send s a message, it gets an ACK from the server along with the muid for the sent message.
Each time a new message is received in the server side, a muid is assigned, sent with the ACK and also sent with the message to every connected user. This way the view will be able to present, for every user, the same sequence at some point in the time.
Each time a new user connects it sends the last muid it has received so the server knows where this user stopped receiving messages. The server could then send as many old messages as you want, depending on the kind of storage you implement:
Full history: I would recommend a database storage with proper indexing
Last N messages: Depending on the size of N you could simply store the last N messages in a fixed size Array and send them, all or the needed chunk, on each reconnection. Keep in mind that this will consume memory so, storing last 1024 messages for 1024 different chats would eat quite a bit of memory, specially if messages are of unlimited size.
Hope it helps
You will have to capture it by your own and store it on server... once user connects you will have to name that data to all connected clients and the messages which you have stored back to the user who has connected. So, you will have to code to broadcast the data to users
By the way what are you using server side? (Node, Erlang , etc)
You can check following link if you are using node.js
http://martinsikora.com/nodejs-and-websocket-simple-chat-tutorial

Sending data to specific client and not to the whole channel

I am currently playing with Faye.js. Upon subscription to a channel I want that specific client to receive an object that would be irrelevant to anybody already in the channel.
How can this be achieved?
More detail:
The object is an array of the last 20 chat comments in the room. Anybody already in the room would have received this object already or been a part of the chats and so it is not required for these to receive it.
Thank you in advance.
The only way I've come across is to generate a client-side GUID. When the client connects, it announces itself to the others through a 'public' channel, you can then use the GUID to send messages directly to this client.
For example, take the piece of code from the answer of this previous question to generate something that looks like a UUID.
You can then do something on the client-side like this:
var guid = guidGenerator();
client.subscribe('/privChannel_' + guid, onPrivateMessage);
client.subscribe('/pubChannel', onPublicMessage);
client.publish('/announce', { 'myId': guid });
function onPrivateMessage() {
// do something
};
function onPublicMessage() {
// do something
};
Your server should always subscribe to the '/announce' channel, and when any message is posted in that channel it should store that id so that it can identify that particular client. Then, the server can use this id to publish to a channel only this client should be subscribed to.
Note however that this is not a good idea for sensitive data. Other clients could also subscribe to '/announce' and farm the guids for malicious purposes.

Categories