Send message to a part of clients using node.js + socket.io - javascript

I've been trying for some days to develop a real-time notification web app using node.js and the socket.io module.
WHAT I HAVE DONE
I have two parts.1) Admins and 2) Users.
So I have initialized two different namespaces on the client side.
Fo example: var socket = io(); for Admins and var socket = io('/Users'); for Users.The time a User sends a message, message goes to ALL of the Admins (1st step made). I am using this command to emit: nsp3.emit('chat message', obj);.nsp3 is var nsp3 = io.of('/Admins'); on the server and obj is a json structure.
WHAT I WANT TO ACCOMPLISH
When a message is sended by some User then the server receives the request, makes a SELECT query to db table based on some criteria and emit the message to a part of Admins who meet these criteria.
Which is the best way to do this?

Related

Socket io Client in ReactJS is getting multiple emits from the server

I am building a chat room with some extra features, and I have a socket io server, as well as a socket io client in ReactJS.
I have it so if someone pins a message or changes the settings of the chat room, it emits the changes to the server, the server saves those changes, and then emits them back out to everyone so everyone is synced.
The settings and pinned messages successfully transfer and are communicated, I have console.logs at almost every step of the transfer, the client logs out a single request, the server logs that it emits a single time, but the client logs that it recieved an emit multiple times, sometimes a couple of times like 2-6 requests, sometime it gives out 60 requests. I'm trying to really control the efficiency, but I have no idea what is causing this
I'm not sure it matters but another thing of note is that the client also connects to a native WebSocket server to get messages from another source
what the client generally looks like is:
effect(()=>{
socket.emit('changeSetting', setting)
},[setting])
socket.on('recieveSetting', (arg)=>{
if(arg != setting){
setSetting(arg);
}
})
the server then looks like this:
socket.on('changeSetting', (arg)=>{
storedSetting = arg
socket.emit('recieveSetting', storedSetting)
})
That's the general structure, so I don't think its an issue of the code, more like if reactJS or connecting to the other websocket causes it to get multiple emits

Handle thousands of sql inserts for realtime chat application using nodejs and postgresSQL

I have a chat application that is built using websockets, NodeJS and postgreSQL. On the client side the user sends the message and socket io server on nodejs receives the event, saves the result in postgreql database using pg npm package and notifies all the connected sockets with new message.
It all works fine until the nodejs socket server starts to receive very large number of messages in small time. For example, 1000 new messages sent from different client browsers to web socket server that needs to insert that into database and then send the newly sent message to recipients.
I want to know how to speed this up?
I am already using connecting pooling on postgresql database server but still insert statements take lot of time when executed in very small amount of time.
Do I need to use some queuing system on server? If so what are options?
Here is may current code snippet:
Client Side:
socket.emit('message', {message: 'Hi', user_id: 125, room_id: 100});
Here is my server side code (node.js+socket.io library)
socket.on('message', function(data){
var query = connection.query(new pg.Query("INSERT INTO message(room_id, user_id,message,sent_datetime) values($1, $2,$3,$4
) RETURNING conversation_message_id", [data.room_id, data.user_id, data.message, new Date()));
query.on('end', function (result) {
io.sockets.in(data.room_id).emit('new_message', result);
});
});
On client side again:
socket.on('new_message', function(newMessage){
//Render logic in message window
});

How synchronise socketIO connection ID's on client and server?

I have a javascript GameClient that uses SocketIO to send messages to a nodeJs server. Multiple users can open the GameClient separately and send messages to the server.
GameClient
GameClient ---> NodeJS Server
GameClient
The server can send messages to specific clients using io.to(socketid).emit(). The code looks something like this:
CLIENT
this.socket = io({ timeout: 60000 })
this.socket.on('connect', () => Settings.getInstance().socketid = this.socket.id)
this.socket.on('reconnect', (attemptNumber:number) => console.log("reconnecting..."))
const json = JSON.Stringify({socketid:this.socket.id, name:"Old Billy Bob"})
this.socket.emit('user created', json)
SERVER (simplified for clarity, just keeping track of one user here)
user = {}
io.on('connection', (socket) => {
console.log('new connection')
socket.on('disconnect', () => {
console.log('user disconnected')
});
socket.on('user created', (json) => {
user = JSON.parse(json)
});
});
// demo code, send a message to our user
io.to(user.socketid).emit("message to one user")
PROBLEM
When the client browser tab becomes inactive for any reason at all, the client disconnects and reconnects and gets a new socket connection ID. This actually happens a lot in Chrome and Safari.
The server only knows the old connection id, so now it can't send direct messages any more. How do I keep the socket connection id synchronised on the client and server?
Since the server also gets a reconnected event, how does it know which user reconnected?
The answer to your question is quite simple: you need a way to identify who is who. And that is not socket.id because this only identifies sockets, not users, as you've already noticed.
So you need some authentication mechanism. Once a user authenticates you can reuse his true id (whether it is simply a name or an integer in a database is irrelevant). And then on the server side you keep a collection of pairs (true_id, socket_id). And whenever a message comes to that user, you broadcast it to all matched socket.io objects.
Edit: So here's the flow:
Client authenticates with the server, the server sends him his own true_id, which the client stores somewhere. The client may also store some session_id or maybe some other mechanism that will allow him fast reauthentication in case of disconnection (note: do not store credentials, its a security issue).
The server keeps track of (true_id, socket_id) pairs in the form of a double way, mutlivalue map (it's an implementation detail what kind of data structure should be used here, maybe two {} objects is enough). If a connection dies then (true_id, socket_id) entry is removed. Note that for a given true_id there still may be some other socket_id alive. And so it doesn't mean that the user disconnected. It only means that this particular channel is dead.
Users don't care about socket_id, they only care about true_id. What you emit is {target_id: true_id, ...} instead of {target_id: socket_id, ...} on the client side, when you want to send a direct message.
When the server receives such message with true_id inside, it retrieves all (true_id, socket_id) pairs and passes the message to all of these sockets (note: maybe you don't even need socket_id, you can simply store socket objects here). Although this is a business logic: do you allow multiple connections per user? I would. There are many edge cases here (like for example a client thinks that he disconnected, but the server thinks he is still connected, etc) and making this 100% correct is unfortunately impossible (due to the nature of networking). But with a bit of effort it is possible to make it work 99% of the time.
If a connection dies then it is your client's responsibility to automatically reconnect and reauthenticate. New socket_id for old true_id is generated on the server side.
Let me emphasize this again: clients don't care about socket_id at all. Because that doesn't identify them. This only identifies a channel. And only the server cares about this information.

socket connection in node js

I have just started working on node js.I have been trying to make chat application using node js. In which a single user can logged in through multiple devices or browsers. If I am not wrong and as I understand each of the browser communicates with different port address since socket connection is defined by IP address and port address hence when the same user logs in from two different browsers server creates two different socket Id.Now I verify if the user is already connected by checking the parameter send to socket info.Then if the user is already connected or the socket is already set for the user then I create connection to change the socket id to previous socket id as .
io.on('connection', function(socket){
socket.id = k;
});
where k is the socket id of previously connected same user
Now when any other client emits message to the current user then Is the socket id is replaced and only one browser gets message or both of them gets message. Is the connection of server is set for both browser or a single browser. Please help me for this. I am still not clear about how socket connection establishes between client and server.
Please improve if I am doing any supposition wrongly Or how do I solve the following scenerio.
Thanks in advance
If I understand your problem correctly, let me try explain in my way. Lets say you have the following code for the server:
var io = require('socket.io')(somePort); //same port for the client to connect, e.g. 3000
io.on('connection', function(socket){
// in here you should define any actions on your primary socket
// for example:
socket.on("hello", function(dataUserSendsWithTopicHello){// overly long variable name to show my point! :)
// do something with hello data
});
// this will go to anyone who is connected and has a handler like above for "hello"
socket.emit("hello", "hello to all who listen to hello topic");
});
A corresponding client would be:
var socket = io.connect('ip:port'); // e.g. localhost:3000 - same ip and port as above
socket.on('hello', function(serverResponseToHello){
// do something when server sends back something on hello
});
// send a hello to the server
socket.emit("hello", "Sending hello to server");
Now if you want to reply to one user only, or a group of people to see some message all together, like in a chat, you could leverage socket.io's room/ namespace implementation (http://socket.io/docs/rooms-and-namespaces/) and create one room for each client, or one room for a group of clients. For this, take a look at this answer: Using Socket.io with multiple clients connecting to same server
To sum it up, there is one ip and one port. Everyone listens to this ip and port and if you open three tabs and you have some implementation like the above, all tabs will be listening to "hello". Using rooms you can group your users and isolate communication so that only the users that the communication is done between the correct users and not all.
Good luck!
I too am fairly new to Sockets (and JS), and I'm trying to make a chat app too but a little differently.
As far as i understand the message will be received only on one browser. A better design would be to let the user connect through multiple browsers/devices. You can maintain a list of all the sockets a user has connected from (if you need it).
If you need a one-to-one chat, maybe you can write some code wherein all sockets the two users connect from are joined into a single room.
socket.room = roomname
socket.join(roomname)
Then you just broadcast the message to that room. That way every sockets both users have connected to will get the message.
socket.to(socket.room).broadcast.emit("message", message);
(I am saving the room info in socket, no idea if that is a good design)
Hope this helps!

Getting the session details via websockets in Node.js

I've created a project in Node.js, users are able to create a 'room'. Users login via a html form which submits their details as a HTTP request. The server then adds a token to their session 'req.session.auth = true'. I want to broadcast socket messages to users where their .auth token is true.
Question:
how can I access session information outside of a HTTP request? whilst using (if correct):
var MemoryStore = require('connect').session.MemoryStore,
sessionStore = new MemoryStore();
e.g.
socket.on('message', function(data){
//Access user session here.
});
There are a lot of things to be said here, but they are all explained better in the following post:
http://www.danielbaulig.de/socket-ioexpress/

Categories

Resources