Socket.io message after database update - javascript

Is it possible to send message (for example using alert) to all users when admin changed something in database?
situation: Users browsing car offers and while doing this admin changed price of few offers --> users gets notifications.

Just couple the event of the database update to an emit like this:
Backend
io.on('connection', (socket) => {
console.log('A user connected');
// handling event from the front-end:
socket.on('clientEvent', function(data) {
// Database update happens before this
socket.emit('databaseUpdate', { description: 'Database is updated'});
});
});
This way every time a database update happens a new event will be emitted to the frontend to all the users which are connected. Your frontend now can listen to it as follows (the frontend who is connected listened to emitten databaseUpdates from the backend):
Frontend
var socket = io();
// now we just log the updated data but in this callback you provide your own implementation.
socket.on('databaseUpdate', (data) => console.log(data.description));
Hopefully you find this answer usefull more info here
source1
Source2

You can use socket.blast() at the end of each db operation.
So, if any user is listening to the blasted message, you can make the API call so that it fetches the new record.
[http://node-machine.org/machinepack-sockets/blast][1]

Related

How to use socket after connect event in socket.io?

sorry for my english.
There is a problem. Inside my app.js server, I added sockets, I use the join event, inside 'connection' event is a function that takes a socket as a parameter, however, I want to push the user into a room, but the name of this room is available inside the model of my REST API part of the server (from the session).
Question. How can I take and push a user who has connected to the right room inside my REST API model? (this model and its service are fired whenever a user requests a page, let's say an analogue of an authorization check). In addition to this problem, there is another service and model that are responsible for adding, for example, some kind of task, this is also a REST API, and so inside this model I would like to send messages to all the necessary users in sockets that a task has been added, EXCEPT the sender himself At the moment I can't do anything at all. It is sent to everyone in general, including the sender, the socket from the connection cannot be thrown in the REST API model
App.js
io.on('connection', (socket) => {
app.set('socket', socket);
socket.on('disconnect', () => {
socket.disconnect(true);
});
});
Controller that sends data to all services, and those in the model
const controller = (ServiceClass, params) => {
return async (req, res, next) => {
const service = new ServiceClass({
session: req.session,
sessionId: req.sessionID,
cookies: req.cookies,
socketIo: req.app.get('socketio'),
socket: req.app.get('socket'),
});
const response = await service.run(params(req));
res.json(response);
};
}
export default controller;
Inside the model that fires on every request to the site from the user, here I'm trying to give the right room
export default class IsLoggedService extends Service {
constructor(context) {
super(context);
}
async execute() {
this.context.socket
.join(`room${userSession.roleId}`);
}
}
I send information to the client about the created task also from the rest api service + model
this.context.socket
.to(`room${userSession.roleId}`)
.emit('test', 'test');
I have already reviewed the entire socket.io documentation, it says everywhere that in order to send a message to everyone except yourself, you need to use a socket, but this does not work at all, it is sent to everyone, including the sender, I also tried to achieve a socket inside the service and model, all to no avail
The most logical implementation method is that you receive all the user through the json object that you receive when sending a message through the socket and implement the logic of the program according to the data.

Socket.io emitting to socket.id when stored in variable not working

as given in Sending message to a specific ID in Socket.IO 1.0, it is possible to emit to a specific client id by using
io.to(socketid).emit('message', 'for your eyes only');
In my node.js application, I am attempting to do the same thing. Basically, when the user submits another's socket.id, the node.js backend is to send the data given to that specific socket id. While the front-end submits the request correctly to the backend, when I attempt to send the data to the id, it does not go through. The "broken" part of the code looks like this:
app.post('/send', function (req, res) {
var post_body = req.body;
var id = (JSON.stringify(post_body.id)).split('"')[1].split('"')[0];
var payload = JSON.stringify(post_body.payload);
var user = JSON.stringify(post_body.user);
console.log(id);
console.log(payload);
console.log(user);
io.to(id).emit('testerEvent', { description: 'A custom event named testerEvent!'});
res.status(200);
});
which is responding to the posted data (data is posted correctly). The client listens for the event 'testerEvent' as follows:
socket.on('testerEvent', function(data){document.write(data.description)});
When the event testerEvent is fired with just io.emit, and not io.to(id).emit, it works fine.
I would appreciate any help on this, as I am just beginning to learn node and socket.io
io.to(id) will send a message to clients that joined a room, so if you have not joined any clients to a room you won't receive the message on a client. To resolve the problem you may try to do client.join(id) when you receive a client socket from Socket.io.

I can't figure out why my Socket.io listener triggers once but then doesn't trigger even if more emits come from the back-end

I'm making a clone of discord and right now I'm trying to implement the online/offline functionality of the server users. I'm trying to implement it like this:
When a user joins a server, I emit a userCameOnline event with the username of the user:
state.socket.emit('userCameOnline', state.username)
Then on the back-end, I listen for that event and once I receive it, I set the socket's username to the emitted username, then push that username to an array of online users and finally, I emit back an event called onlineUsers:
socket.on('userCameOnline', (username) => {
socket.username = username
onlineUsers.push(socket.username)
console.log(onlineUsers)
socket.emit('onlineUsers', onlineUsers)
})
And this is the onlineUsers listener on the front-end that sets onlineUsers property to the server:
state.socket.on('onlineUsers', (onlineUsers) => {
console.log(onlineUsers)
server.onlineUsers = onlineUsers
})
Now here's the problem. The onlineUsers listener works when I load the page the first time, however, when I open a second browser and join the chat with another account, the client emits these events again with the new user:
state.socket.emit('userCameOnline', state.username)
I know this is working fine as I console.log(onlineUsers) on the back-end and see that the array indeed has 2 users once the second client has joined. This means that this works:
socket.on('userCameOnline', (username) => {
socket.username = username
onlineUsers.push(socket.username)
console.log(onlineUsers)
socket.emit('onlineUsers', onlineUsers)
})
Unfortunately, the onlineUsers listener on the first client doesn't trigger which means that the onlineUsers property of the server doesn't get updated with the newly joined user. I've been banging my head for some time now and I can't figure out why is this happening. I've been following the trail and console.logging everything but I still can't figure it out.
This is why I am wondering why does this:
state.socket.on('onlineUsers', (onlineUsers) => {
console.log(onlineUsers)
server.onlineUsers = onlineUsers
})
Triggers once I load the page and then doesn't trigger anymore even though I'm emitting the event from the back-end every time a new user joins the server?
So, if i understand your problem then instead of emitting in the Back-end:
socket.emit('onlineUsers', onlineUsers)
You should emit :
io.emit('onlineUsers', onlineUsers)
Because by emitting with socket.emit() you will end up emitting only to the same client that emitted to the server in the first place.
As with io.emit() you will emit to all of your clients.
Assuming that you are using something like :
const io = require('socket.io')(server, {(your_args)})
If you want to check for further information on how to use the emit function
check out this page https://socket.io/docs/emit-cheatsheet/ from their website.
Finally i would highly recommend you to check out their API documentation and other blogs about it

Emit event for particular user if login functionality in application in Socket.io with Node.js

I have used methods socket.on and io.emit, And i got response to all users. But, i want to get response for particular user.
But my application contains login functionality and i followed this post on stackoverflow, and they are saying we need unique userId and socketId in an object for a particular user to emit an event for a particular user.
But i am getting the userId after login, But we want it when user connect to app.
So can anyone please help me with the same?
In your node.js, create a global array 'aryUser', each element contains the socketid and loginid.
node.js onConnect (new connection), add a new element to the array with the socketid and set loginid = empty.
after the user login, emit an event from client to the server, e.g:
socket.emit('userloginok', loginid)
in node.js, define a function:
socket.on('userloginok', loginid)
and in this function, search the aryUser with the socketid and replace the empty loginid inside the array element with the parm loginid.
in node.js, define the function:
socket.on('disconnect')
and in this function, search the aryUser, use aryUser.splice(i,1) to remove the user just disconnected.
that means, aryUser contains all users connected, some of them logined, some of them not logined. And you can use the socketid of the array to send message to particular user, and/or all users.
Example Source Code:
server.js
http://www.zephan.top/server.js
server.html
http://www.zephan.top/server.html.txt
rename server.html.txt to server.html, put server.html and server.js in the same directory, and run:
node server.js
Yes, you definitely need socketId in order to send and receive messages between two specific users.
UserId is required just to keep track of socketId associated with the particular user or you can manage it with some other way as well that's up to you.
As per your question, you have userId of the user and you need socketId of that user! So, in this case, you can pass userId when that particular connects to a socket server from the client side as shown in below snippet,
const socket = io(this.SOCKET_SERVER_BASE_URL, { query: `userId=${userId}` });
And you can read this user on nodejs server like this,
const userId= socket.request._query['userId'],
const socketId= socket.id
Now store this socketId in somewhere, for example, Redis or some sort of caching mechanism again up to you, just make sure fetching and retrieval should be fast.
Now while sending a message just pull the socketId from your cache and emit the message on that socketId by using below code,
io.to(socket.id).emit(`message-response`, {
message: 'hello'
});
I have written a complete blog post on this topic on both Angular and AngularJs, you can refer those as well.
Edit 1:
Part 1 =>
When your user completes the login request, then make the connection to the socket server.
Assuming you are using React Or Angular After a successful login you will redirect your user to home component(page). On the Home component(page) make the socket server connect by passing the userId just like this,
const socket = io(SOCKET_SERVER_BASE_URL, { query: `userId=${userId}` });
P.S. you can get userID from URL or maybe using a cookie that is up to you.
Once you receive this socket connection request on the server, then you can read the userID query and you can get socketId associated with it and store it in cache like this,
io.use( async (socket, next) => {
try {
await addSocketIdInCache({
userId: socket.request._query['userId'],
socketId: socket.id
});
next();
} catch (error) {
// Error
console.error(error);
}
});
Part 2 =>
Now, let's say you have a list of the users on the client side, and you want to send a message to particular users.
socket.emit(`message`, {
message: 'hello',
userId: userId
});
On the server side, fetch the socketId from the cache using UserId. Once you get the socketId from cache send a specific message like this,
io.to(socketId).emit(`message-response`, {
message: 'hello'
});
Hope this helps.

Socket.io, message to yourself

Socket.io doesn't display messages send on yourself ip.
For example
var id = 333;
socket.broadcast.to(id).emit('user', user);
It working good, but message is only in client #333, but user than sent message, do not have a copy in the message client.
I wanted to solve in this way, but it does not work
socket.broadcast.to(socket.id).emit('user', user);
Why?
Without more code its hard to say what you want but one thing is certain in order to send a message to a single user you must use that socket object and use socket.emit
As far as i know broadcast is only used to tell everyone except for yourself.
What i usually do when it comes to keeping track of users is i have the following:
var userList = [];
io.on('connection', function (socket) {
socket.on('userData', function (userDetails) {
userDetails.socket = socket;
userList[userDetails.id] = userDetails
});
});
Basicly when a user connects to my socket and the page for the user is fully loaded it sends its id (or a token if you wish) i then map the user's socket into the list so i can quickly pick it up again if i wish to send to that user.
An example could be:
user.id = 33 connects to our server
Once loaded the users emits to our server userData function
The socket is then taken and put into the list at row 33
When we need to we can this use the following code to get the users socket:
socket = userList[33];
or if we have the object:
socket = userList[user.id];
I hope this helps you.
For this, you can use socket.emit('message').
socket.emit: Emit for only one socket.
Hope this will help you. You can also check out this link: socket.io send packet to sender only

Categories

Resources