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.
Related
i'm building an angular app that will make about a thousand people to connect simultaneously to book a ticket. I want only "XYZ" of them to access simultaneously at the registration Angular component. The other ones will see a "waiting room" component until it's their turn.
I set up the whole thing like this:
User enters the page.
I make an http call to expressjs server
The server checks if the "connections" collection constains less than XYZ docs
If true, it unlocks the user registation component and with an http post req, it creates a new doc in the db. if false it leaves it hidden and shows up the waitingroom component
When user leaves the page, his doc in "connections" collection gets destroyed with an http delete call.
Fully working.
The problem is now that i want to create a kind of "priority" system, because, going like that, if you just refresh you may be lucky and get access, even if you are soon arrived and there is who is waiting since 1990's. So i introduced a "priority" system. When the user makes the first http call, if user is not allowed, the server creates a timestamp and pushes it into an array.
const timestamps = []
.
.
.
// this below is in http get req
Connessione.countDocuments({},(err,count)=>{
if(count<=nmax){
console.log("Ok")
res.status(200).json({allowed: true})
}
else{
const timestamp = req.params.timestamp;
timestamps.push(timestamp);
console.log("Semo troppi")
res.status(401).json({allowed: false})
}
});
The idea is to listen to db changes, and when there is just XYZ-1 in the db. Make a call to the first timestamp's angular frontend to say him: "Hey there, if you want we're done. You can go" and unlock him the access to registration component.
The problem is that i can't make continuous http requests every second from angular until there's a free place...
Is there any method to send a request at the server, and when server says OK, calls angular and says "Hey dude. You can go!"?
Hope you understood my question. If not ask me in the comments.
Thanks in advance
Even i had trouble with sockets in the beginning so i'll try to explain the concept in a simple way, Whenever you write an API or Endpoint you have a one way connection i.e. you send request to server and it return back some response as shown below.
Event 1:
(Client) -> Request -> (Server)
Event 2:
(Client) <- Response <- (Server)
For API's, without request you cannot get response.
To overcome this issue as of now i can think of two possible ways.
Using Sockets, With sockets you can create a two way connection. Something like this
(Server) <-> data <-> (Client)
It means you can pass data both ways, Client to server and Server to client. So whenever an event occurs(some data is added or updated in database) one can emit or broadcast it to the client and the client can listen to the socket and receive it.
In your case as it's a two connection you can emit the data from angular and
I've attached few links at the bottom. please have a look.
Using XML/AJAX Request, This is not a preferable method, using setInterval you can call the server in every 5 seconds or so and do the operation needed.
setInterval(ajaxCall, 5000); //5000 MS == 5 seconds
function ajaxCall() {
//do your AJAX stuff here
}
Links:
https://socket.io/docs/
https://alligator.io/angular/socket-io/
Probably I haven't understood nodeJS at all, but I build a running client and server app, which sends data trough socket.io.
It works perfectly, but when I open the site on another machine, the content is identically.
When using PHP, every machine running the script has a unique instance of it, so I can make database calls that are only visible to the particular user.
Hopefully this is understandable.
EDIT:
Let's say I've got a normal socket.io setup.
When clicking a button, the following is fired.
socket.emit('getImages', 'someData');
this will make the server send 2 images back, which I will then display on the site.
This works fine for one user. But if there are multiple users at the same time, the images will get changed on every user's site, not just on the one, which fired the function.
On your server:
socketServer.on('connection', function(socket){
console.log("A Client has connected.");
socket.on('disconnect', function(){
console.log("A Client has disconnected.");
});
socket.on('getImages', function(data){
//Do something with the image/data here
//send something to the socket that emitted getimages command
this.emit.('commandhere', datahere);
/* you can also do this.broadcast.emit('commandhere', datahere) to broadcast
all connected sockets except the one who emitted the command
or socketServer.emit('commandhere', datahere) to broadcast all connected
sockets. */
});
});
I am running Node.js and Socket.io on Linux Server.
I've created an online chat room/lobby, I am wondering how can I create like a daemon who has a role of user, he is connected to lobby always and is monitoring lobby, and messages that users post. When specific criteria is matched - report back to server.
For example, some user posts too many messages per minute, the bot would send message to user saying to slow down, if user continues bot would send request to server saying to kick that user.
I am new to node.js and socket.io, so I am not sure how to implement it.
I don't want to hard code every rule or criteria into server itself.
I don't think your way will be working. The way on top of my head is doing it on server. Socket.io can fire any event on client side and send to server, so you can ask server to listen to certain event and handle your logics accordingly on server. Below is some sample code for your reference.
client side:
this event will fire whenever client sends a message.
$("#msgbutton").click(function(){
socket.emit("message","some message client send");
});
server side:
socket.on('message', function(msg){
var now = new Date();
var lastsent = socket.lastsent; //socket is an object and you can store lastsent datetime to it
var diff = now.getTime() - socket.lastsent.getTime();
if (diff/1000 > 2) // if message interval is larger than 2 seconds
{socket.to(room).emit('message',msg); // send message to whole room}
else if
{ // maybe send a warning event to user }
});
The code is not tested, and only consider the time difference between current msg and last message. If you want to monitor the message sent event over certain time course, you will have to write your logics on server to do that. Hope this can give you some pointers.
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
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