Is it possible to show live data from MongoDB via socket.io? - node.js

So, I would like to stream live data from MongoDB to my web, and I really don't know how can I handle live connection by sockets.io. The data is pushed to database from an external source but when I append the data on MongoDB compass nothing happened.
This is my code:
const mongo = require('mongodb').MongoClient;
mongo.connect('', function (err,db) {
if (err) {
throw err;
}
console.log("Mongodb Connected...");
io.on('connection', (socket) => {
console.log("Someone connected.");
Post.find().sort({_id:-1}).limit(1).lean().then(req =>{
socket.emit('temp', {temp: req});
})
});
});

Few things to consider while working with real-time reports
Connect your socket with server and client.
When Something happened on the server (in your case when data insert into DB) emit event as you are already doing on the above code.
Listen to your event from client side (browser) (You will get some signal or data from the server)
Once your received particular signal (event) from the client side, Hit particular URL using ajax to get data from the server and display it as per your requirements.
I Hope it will help you to solve your problem.

Related

Socket.io listener getting skipped on the client-side while there is an emitted event

I am facing this weird issue. I am not a veteran of using Socket.io. I have been exploring this library as the app I am building needs a remote playing feature wherein players create invitations to other players so that they can use those invitations to join the game remotely. I am using React on the front end (client-side), and on the server side, I am using the Nodejs Express framework with Socket.io. I have also installed client-side Socket.io for React. The basic implementation is all working fine. When there is a new user accessing the client-side app, Server-side socket.io listens to the connection. Any events triggered by the client also get reported on the server side. I am also able to broadcast the events back to all the connected clients using the socket.broadcast.emit() method.
I am trying to store the past events (basically, these are the invitations created by the currently connected players) in an array and then emit the stored array for the new connections so that the new users will see the past events(invitations). Below is my implementation on the server side:
//Array to store previously emitted events
const activeInvites = [];
//SocketIO connections
io.on("connection", (socket) => {
console.log(`⚡: ${socket.id} user just connected!`);
//Listen to the new invites
socket.on("newInvite", (invite) => {
activeInvites.push(invite);
socket.broadcast.emit("newPrivateInvites", invite);
});
//Publish all previously created invites to the new connections
io.emit("activeInvites", activeInvites); //new connections emit this event however the client won't listen to "activeInvites" event
socket.on("disconnect", () => {
console.log(`🔥: ${socket.id} user disconnected`);
destroy();
});
function destroy() {
try {
socket.disconnect();
socket.removeAllListeners();
socket = null; //this will kill all event listeners working with socket
//set some other stuffs to NULL
} catch (ex) {
console.error("Error destroying socket listeners:", ex.message);
}
}
});
And, below is my client-side implementation:
useEffect(() => {
socket.on("activeInvites", (invite) => {
console.log(invite);
}); //a new connection client skips listening to this event. Can't understand why.
socket.on("newPrivateInvites", (invite) => {
setPrivateInvites((existingInvites) => [...existingInvites, invite]);
});
//I have commented below code. Even if I uncomment it, no difference
// return () => {
// socket.off("newPrivateInvites");
// socket.off("activeInvites");
// socket.removeAllListeners();
// };
}, [socket, privateInvites]);
//Below is the handler function I use to open up a Sweetalert2 dialog to create an invite
const createMyGameInviteHandler = () => {
swalert
.fire({
title: "New Invite",
text: "This will create a new game invite and unique joining code that you can share with your friends",
iconHtml: '<img src="/images/invite.png" />',
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yeh! Let's Go!",
customClass: {
icon: "no-border",
},
})
.then((result) => {
if (result.isConfirmed) {
player.gameId = "1234";
setMyGameInvite(player);
socket.emit("newInvite", player); //This is where I create a new invitation event
}
});
};
In the above code, the "activeInvites" event is getting skipped by the new client even after socket.io on the server side triggers a new event after the new connection is created. Note that I am using io.emit() to emit the event to all the connected clients. So, even new clients should also listen. I am not able to see where the problem is. Could you please help me with this?
I tried to store the events generated by the client and consumed by the server in the past so that I could serve those events to the new clients when they establish the connection. I was expecting that io.emit() method would emit the event that will be consumed by all the clients including the new clients. However, new clients are skipping listening to this event. I am using useEffect hook in a react component.

Accessing the Data Object of Socket.IO-Server from the Socket.IO-Client

In socket.io server a property can be added to the socket.data object. How do I access such a property at the client side (socket.io-client)?.
// Server code
io.on('connection', socket => {
socket.data.customId = getCustomId();
io.emit('connected', {success: 'true'})
})
// Client code
socket = io('http://localhost:5000');
socket.on('connected', data => {
console.log('SOCKET_DATA:', socket)
console.log('SOCKET_CUSTOM-ID:', socket.data.customId); // produces 'undefined'
})
I would like to access the customId I added at the server from the client side. The data attribute don't even exist on the socket object displayed at the console at the client side.
If you wanted some way to have access to that, you would have to create some request that sends to the server. Only the server stores that information. You could do something like the following on client side:
socket.emit("getCustomId", (id) => {
console.log("SOCKET_CUSTOM-ID:", id);
});
Then the server can listen and respond with the custom id:
socket.on("getCustomId", (callback) => {
callback(socket.data.customId);
});
That callback parameter on the server side connects back to the unnamed ES-6 function declared in the socket.emit("getCustomId"); call, which you can see here on this SO question about socket.io callbacks

how to manage multiple socket connections for a chat app with socket.io, react native, nodejs

I'm wondering how to dynamically create chat rooms with socket.io. I've seen this question: What is the proper way to manage multiple chat rooms with socket.io? , but it's not quite what I'm looking for. I want to open chat rooms with an id that I predetermine, so that I can keep track of different conversations within my db, client, etc. I've figured out how to handle the emitting of new messages to the appropriate client, but I can't figure out how to establish the connection dynamically, or if I have to manage multiple sockets at once for many users across many chat rooms.
Heres the node.js code:
websocket.on('connection', (socket) => {
console.log(socket);
clients[socket.id] = socket;
socket.on('5b17803f134204f7f3e274e0-5b17703f134204f7f3e274e0', (message) => onMessageReceived(message, socket));
socket.on('5b17803f134204f7f3e274e0-5b17703f134204f7f3e274e0-join', (chatInfo) => _sendExistingMessages(chatInfo, socket));
});
As you can see, I wish to replace the '5b...' strings with something dynamic. The client code to make this connection is just one line:
this.socket = SocketIOClient(port);
Is there a way to do this? A follow up question would also be how do I manage all of these different sockets? A set of sockets perhaps? Any help would be appreciated, thanks!
With socket.io you generally only need to do a socket.join() on the room you want them in, which can be your dynamic room name. From there, you can just emit an event to the room.
io.on('connection', function (socket) {
socket.join('5b17803f134204f7f3e274e0-5b17703f134204f7f3e274e0', function (err) {
if(err) {
throw err
}
io.to('5b17803f134204f7f3e274e0-5b17703f134204f7f3e274e0').emit('joined', {})
})
})
If the above example doesn't work, you may need to setup another event handler on the socket, and then have your client send that event to join the room, from there you can fire a callback with the return data to the client
socket.on('joinRoom', function (data, callback) {
socket.join(data, function (err) {
if(err) {
return callback("error")
}
return callback("joined")
})
})

Websockets using angular and Nodejs: How to send data to specific client

I am trying to use websocket.io with nodejs and angular. I am trying to build a one-to-one chat application. Here is snippets of my code:
server.js
app.io.on('connection', function(socket){
console.info(`Client connected [id=${socket.id}]`);
socket.on('disconnect', function(){
console.info(`Client gone [id=${socket.id}]`);
});
});
sendmessage.js
router.post("/auth/sendMessage", function(req, res) {
//rest api to handle send message
//mongodb insert
app.io.emit('new-message', { message: message});
}
Angular Client
this.socket.on("new-message", function(data) {
if (
data.message.conversationId === self.conversationId &&
data.message.sender === "customer"
) {
self.messages.push(data.message);
setTimeout(function() {
self.messagesDiv.nativeElement.scrollTop =
self.messagesDiv.nativeElement.scrollHeight;
}, 100);
}
});
Now, the problem that I am facing is new-message will send message to all the listeners. Although, I am handling the logic on the client side, to only show the message if it is sent by specific conversationId, this should be handled at the server end only due to security issues.
So, I want to be able to send to specific users only. I think this can somehow be done using socket.id which would be unique for each connection. But how can I pass this socket.id from client to server, so that server knows on which client it needs to send the data?
There are two things here, app.io and socket. In the first snippet, you use app.io.on('connection', function(socket){. This socket is the new connection. You can store this socket object somewhere in the database or in memory.
Now, app.io.emit will send the message to all the clients, while this socket that you stored somewhere will send the message to that particular client/user on socket.emit.
In short, you need to do
router.post("/auth/sendMessage", function(req, res) {
//rest api to handle send message
//mongodb insert
socket.emit('new-message', { message: message});
}
Here is a small tic-tac-toe game I made using sockets. It will give you more insight on how to use sockets. This is not perfect but you will still understand how to use sockets.
tl;dr save socket from app.io.on('connection'... and use socket.emit to send messages to that particular client.

Listen for TCP connection from connected object on 3G network

I have a connected object that works on 3G network and that is sending data to my IP on a selectable port.
I would like to read the data sent from this object on a node.js program because all my API on my server is on node.js
For this I tried to create a 'net' server like this :
var net = require('net');
var server = net.createServer(function (socket) {
socket.on('data', function (data) {
var StrData = data.toString('ascii');
fs.appendFile("test.txt","data received : "+ StrData, function (err) {
if (err) throw err;
console.log(StrData);
});
});
});
server.listen(2000, '0.0.0.0');
And I am getting all the data sent by the object to my "test.txt" file as wanted. The problem is that it seems that the connection is closed by my server after receiving the first data, so my connected object have to create another connection every time and just can send the first data.
My question is:
How can I let the connection opened so the object can send all the data?
I also tried 'socket.io' and 'http' but I can't get what I want.
It is hard to debug the issue with the given code, can you try to add an error listener to your socket and see if any errors are triggered:
socket.on('error', (err) => {
console.log(err);
}
My guess is your client is closing the socket, thinking the request is timed out (since you are not returning a success response of some sort). net.createServer creates a TCP server which expects a response for all requests.

Resources