Handle chat system with socket.io, nodejs and mongodb - node.js

I have to create a chat system for our client online shop, we use nodejs/mongodb/socket.io.
I just tested if the realtime conversation between my nodejs and a simple html page is working :
const server = app.listen(app.get('port'), () => {
console.log("working");
});
var io = require('socket.io').listen(server);
io.on('connection', function(socket){
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
socket.emit('I just emit here for test', 'hello');
});
This code just working, now the fun part is to be able to make a shop manager discuss to a client, but clients shouldn't able to discuss between them (I have already a "clients" and "shop manager" collection ) like
below picture :
So, could someone tells me what is the best workflow to achieve this?, it means how to identify a client? and begin conversation to him? i am a bit lost with socket.io ...
Thanks for your help.

Create a message schema which will store conversations between client and manager.
Create a schema which will hold rooms or communication IDs.
Whenever a client logs into your system, show him the list of rooms, and when a client picks any room, show him the conversation.
Now, how to create a room?
Whenever a client wants to communicate with a manager (let's use ClientA and ManagerA), check if the conversation already exists or not. If a communication already exists, create a unique room like "clientA-room-managerA" and add both the parties to that room, store all the conversations in existing messages schema.
If the communication does not exist, create a room like "clientA-room-managerA" and then create a chat record in the schema which will hold communication Ids, and then start the room same as before "clientA-room-managerA"
By this way you should be able to create multiple chat records for a client and manager.
A client will not be able to communicate with other clients
A Manager can have communication with various clients
Consider a manager with user id: 123456789 and client with 0987654321, then you can create a room like:
var room = manager.user_id + "-room-" + client.user_id;
// room = 123456789-room-0987654321
//then join the client and manager to the room
manager_socket.join(room);
client_socket.join(room);
//you can send a message in a room:
io.sockets.in(room).emit('new_message',{"msg":"hi there"});
PS:
This is a kind of group chat where the group contains 2 members i.e. Client and a manager. For reference you can see this links:
http://psitsmike.com/2011/10/node-js-and-socket-io-multiroom-chat-tutorial/
https://github.com/jgonera/socket.io-multichat

In socket.io each socket has an individual ID which you can use to communicate between particular sockets. You can assign a particular value to the ID if you want, for example the user's MongoDB _id, for example:
this.userEmit(userID).emit('got user settings', settings);
// where userEmit is a custom function that will handle an error case when the id can't be found
You can also broadcast to specific "rooms", whereby only sockets that are members of that room will receive the message, e.g.:
io.sockets.in(groupID).emit('update group status', {
groupID: groupID,
onlineMembers: x.length
});
See their documentation for some examples: https://socket.io/docs/rooms-and-namespaces/

Related

send message to specific client using soocket.io while socket id changes rapidly

I'm running a chat server using node.js and socket and want to send message to specific client.I use socket.id to send the message to the defined user,like this:
io.sockets.in(user socket.id).emit('message',message)
but there is a problem:
user remains connect but socket id changes rapidly(About once per second) so i can not use socket.id.I tried socket.join(user email) to use user email instead of socket id but after socket id changes it does not work any more.
what's the best way to solve this?session-id?If yes,how?chat application for clients runs on android device.
This is my code:
io.on("connection", function(socket) {
socket.on("login", function(useremail) {
socket.join(useremail);
});
//Here i want to send message to specific user
socket.on('messagedetection', (senderNickname,messageContent,targetuser) => {
//create a message object
let message = {"message":messageContent, "senderNickname":senderNickname}
//targetuser is the email of target user,joined to the socket in login
io.sockets.in(targetuser).emit('message',message)
});
socket.on('disconnect', function() {
console.log( ' user has left ')
socket.broadcast.emit("userdisconnect"," user has left ") });
Making my comment into an answer since it was indeed the issue:
The problem to fix is the rapidly disconnecting/reconnecting clients. That is a clear sign that something in the configuration is not correct.
It could be that network infrastructure is not properly configured to allow long lasting socket.io/webSocket connections. Or, if your system is clustered, it could be caused by non-sticky load balancing.
So, each time the connection is shut-down by the network infrastructure, the client-side socket.io library tries to reconnect creating a new ID for the new connection.

better approach for one to one and group chat nodejs Socket.io

I am implementing one to one and group chat in my application in NodeJs using socket.io and angular 4 on client side. I am new to socket.io and angular 4.I want to ask what is better approach for this e.g if user want to send a message to specific user or it want to send a message to group of users.
According to my Rnd should I keep the obj of all connected users and that obj contain the socket id of that user with his user name (email or what ever ) so that if some user want to send message to some one we should need his user name and we can access his id through his user name .
Or is there any solution except this ?
And where should i keep that obj of user and socket id global variable or database ?
One-to-one and group chat is very similar. If we use rooms in socket.io https://socket.io/docs/rooms-and-namespaces/#.
In one-to-one only 2 users are in the same room. where as in a group chat more than 2 people can be in the same room.
So when a person sends a mesage, they send it to the room they belong to and want to chat with instead of sending it to individual users. Then, everyone in that room, whether its one other person or multiple people will receive it.
- Node.js
Join a client to a room
io.on('connection', function(client){
client.join(conversation._id)
});
Emitting a message to a room
client.broadcast.to(conversation_id).emit('message:send:response', {
msg: res.msg,
conversation_id: res.data._id
});
- Angular
Listen to emitted messages
getMessages(conversation_id) {
let observable = new Observable(observer => {
this.socket.on('message:send:response', (chat) => {
if (chat.conversation_id === conversation_id) {
observer.next(chat.msg);
}
})
});
return observable;
}

Is there an alternate way of sending a private message with Socket.io (1.0+)?

Im working on a simple session based app shared by a session code in the URL. I decided to generate and assign a shorter user friendly unique ID for each client who connects to a socket, and the client who creates a session causes a socket.io room to be created with his ID.
I didnt realize until later that the private messaging mechanism in socket.io relied on each client being assigned to a room named by their ID. This means that because my room for a session is named after the creator's socket ID, using .to() will not message that client, but rather all of the clients now assigned to that room.
I could remedy this in ways that would require some re-design, but first I wanted to ask if there is an alternate way of sending a message to a specific client via his/her ID.
/*create an array of clients, where key is the name of user and value is its unique socket id(generated by socket only, you do not have to generate it) during connection.*/
var clients = {};
clients[data.username] = {
"socket": socket.id
};
//on server side
socket.on('private-message', function(data){
io.sockets.connected[clients[data.username].socket].emit("add- message", data);
});
//on client side
socket.emit("private-message", {
"username": userName,
"content": $(this).find("textarea").val()
});
socket.on("add-message", function(data){
notifyMe(data.content,data.username);
});

Design choice using node.js and express and socket.io

I want to make a web app where every user can create a chat room that other users can join. I would like to have a main node server managing the rooms, and every time a user creates a new room, a new chat server should be started by the main server and it should manage the room.
My question is, how can I make the new server start in node.js and how can I manage it?
Socket.io allows you too use the room feature and have the behavior you want (separate chat rooms) without running a separate chat server. Running a separate chat server is not really convenient in node.js because it means running another process, and it makes communication between the main server and the chat servers extra complicated.
What i would advise is using that feature and adopt the following kind of design:
io.on('connection', function(socket) {
//initialize the object representing the client
//Your client has not joined a room yet
socket.on('create_room', function(msg) {
//initalize the object representing the room
//Make the client effectively join that room, using socket.join(room_id)
}
socket.on('join_room', function(msg) {
//If the client is currently in a room, leave it using socket.leave(room_id); I am assuming for the sake of simplicity that a user can only be in a single room at all time
//Then join the new room using socket.join(room_id)
}
socket.on('chat_msg', function(msg) {
//Check if the user is in a room
//If so, send his msg to the room only using socket.broadcast.to(room_id); That way, every socket that have joined the room using socket.join(room_id) will get the message
}
}
With this design, you're simply adding listeners to event, and once set up, the whole server is running fine without having to deal with concurrency or sub processes.
It's still very minimalist and you'll probably want to handle a few more concepts, such as unique nicknames, or password authentication etc.
But that can easily be done using this design.
Have fun experimenting with socket.io and node.js!

how to get number of socket connections using socket.io

Is there a way to get the number of connections in socket.io?
I want to display a message on my site that says "x users connected right now"
Basically if I did a socket.broadcast I want to count how many connections that would go to.
You can use
io.sockets.clients().length
Basically io.sockets.clients() returns Socket instances of all clients. If you're using rooms then you should better use
io.sockets.clients('room').length
because it returns socket instances of all clients in a particular room
Using this code Server site
var noOfUser=[];
socket.on('someEventFromClient',function(data){
//User name must unique
socket.username=data.username;
noOfUser.push(data.username);
//Now you can emit no of user to client are any where
console.log('NO of user:'+noOfUser.length);
});
socket.on('disconnect',function(){
for(var i=0;i<noOfUser;i++)
{
if(noOfUser[i]==socket.username)
{
noOfUser.splice(i,1);
}
//Now you can emit no of user to client are any where
console.log('NO of user:'+noOfUser.length);
}
});
Client side:
when user connect socket server emit this event
socket.emit('someEventFromCLient',{username:'someuniqueID'});

Resources