I have created a webapp that was working fine as a standalone app without the need of nodejs or anything, but now I am trying to migrate it to Expressjs/nodejs.
The problem that I am having right now, is that I want to be updating the data on that website dynamically, in realtime without the user having to refresh the webpage. The webpage is basically just showing some values, and they need to refresh every half a second or every second to make it appear realtime.
First I started off with EJS, but I couldnt find a way to do this with EJS and most answers that I found pointed out that I have to use something like socketIO to get this done and so I did.
My socketIO code on the server:
io.on('connection', (socket) => {
setTimeout(function() {emiter(socket)}, 1000)
console.log('a user connected');
});
function emiter (socket) {
socket.emit('MyEvent', GetData.RData.R[" 1"].Val);
}
My socketIO code on the front end:
var socket = io.connect('http://192.168.0.2:3000')
socket.on('MyEvent', function (message) {
$("#test").html(message);
})
It is sending the data, but it is not refreshing when new data is available.
GetData.RData.R is being populated by an ajax call that is executed every 1 second to retrieve new data from a device.
If I manually refreh with F5 new data is displayed.
Related
I am trying to make an API that will send back a real-time JSON. I am using NodeJS with ExpressJS, and Socket.io, and the problem is that res.send can not be sent more than one time; And, I really don't know how to send my (real-time) data without asking the refresh of my page.
Basically, I made a timer that changes the value every second.
I also tried to send a file, but I can't use this method, because my iOS app is asking a JSON data without HTML code
setInterval( function() {
var msg = Math.random().toString();
io.emit('message', msg);
console.log(msg);
res.send(msg);
}, 1000);
Maybe, there is another framework than Express than I could use and could refresh my data automatically? The console.log line works well and my data is updated every 1000ms.
Thank you in advance
how to avoid new socket connection on page refresh? I have a game which starts on two socket connections in a room but during the middle of the game i refresh the page and the game progress is lost and a new game starts if there is a new opponent waiting.I want this to be avoided , any idea? Plese help , i am really stuck into this
server.js
function onClientdisconnect() {
console.log('player disconnected with id ' + this.id);
//send message to every connected client except the sender
this.broadcast.to(this.room_id).emit('remove_player', {id: this.id});}
io.on('connection',(socket)=>{
console.log('user connected ' + socket.id);
socket.on('disconnect', onClientdisconnect);
client.js
var socket =io();
// socket connection
socket.on('connect',function(){
socket.emit('new_player_GK',{
id:socket.id
});
console.log('connected');
});
You can't, the websocket connection is closed automatically when the page is closed (refreshed).
You would have to implement your own session logic, maybe store cookie/localStorage data on the client side and restore the (previous) client data on page load.
If your game data is stored on the server, you would have to implement some sort of authentication so you know that game data X is from user Y, so when user Y (identified based on cookies) loads the page again the server returns his previous data X.
If you need a more specific example you would first have to explain what data you want to be persisted between page loads, keeping in mind that persisting the websocket connection is not possible. I would recommend instead making your game work more like a SPA so you entirely eliminate the need to refresh (this still won't maintain progress if user intentionally refreshes the page or closes the tab).
I need to continuously update data on the client based on DB changes. I'm thinking about having a 5 second interval function that repeatedly gathers all the DB information and use Socket.IO to emit the data to the client.
Currently, I'm doing this on the client itself without socket.io, just repeatedly doing a REST call to the server which then handles the data.
My question is: Are either of these methods efficient or inefficient and is there a better solution to solve what I'm trying to achieve?
Ryan, you can try using MongoDB's collection.watch() which fires an event every time an update is made to a collection. You would need to do that within the socket connection event for it to work though. Something along these lines:
io.sockets.on('connection', function(socket) {
// when the socket is connected, start listening to MongoDB
const MongoClient = require("mongodb").MongoClient;
MongoClient.connect("mongodb://192.168.1.201")
.then(client => {
console.log("Connected correctly to server");
// specify db and collections
const db = client.db("your_db");
const collection = db.collection("your_collection");
const changeStream = collection.watch();
// start listening to changes
changeStream.on("change", function(change) {
console.log(change);
// this is where you can fire the socket.emit('the_change', change)
});
})
.catch(err => {
console.error(err);
});
});
Note that using this approach will require you to set up a replica set. You can follow those instructions or use a Dockerised replica set such as this one.
I need more details to make sure but it doesn't sound like a good solution.
If the data you need does not change rapidly, like let's say in seconds, each of your connection still polling every 5 seconds and that's kind of wasting.
In that case you might just trigger an event where the data got changed, then you can push the message through sockets that are active.
So currently my setup is I have a standard app.get('/', etc for my index and inside here, I have my io.on('connection', function etc). Now the goal is so that every time someone connects to only the homepage i can get that socket with io.on(connection and send things to it that way, and my syntax and all is fine however i believe having my io.on('connection' inside a route is my issue.
The problem: Whenever someone connects to my website after i start the server, it works great, for debug examples i have a console.log inside of it and its called once and we are good. However if that same person reloads the page my io.on('connection' is called again, and this time iw ill get 2 console.log's... when I again reload I then get 3 and so on and so on, no matter if i close the page and reopen it or come from a different ip. It seems as if the connection isnt closed when I reload and all the still hanging connections are recalled when I reload.
I know this is a little unorthodox with me not posting my code. Its not the syntax, here is an example of essentially the set up described. Oh and also i need access to the req input from the app.get which is why its in there in the first place, I have passport variables saved in it.
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
io.on('connection', function(socket){
console.log("1 connection");
});
});
I hope this explains my issue well enough. When i looked for answers first i found a bunch of stuff about routing, but was confused. Any help is appreciated!
For what I got from the question and the comments.
You are doing it wrong way. You should never put the ONs and EMITs of socket connection where they are called multiple times as they are appended every time.
for example : first time this is called
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
io.on('connection', function(socket){
console.log("1 connection");
});
});
the io.ons['connection'] has the value
function(socket){
console.log("1 connection");
}
second time you call it the callback is appended again. and the value of io.ons['connection'] is now
function(socket){
console.log("1 connection");
}
function(socket){
console.log("1 connection");
}
So it prints console.log two times
SECOND :
if you want to do the further work after the user is logged in.then you need to verify the user here, you can use a socket.emit('init',..... from client side
and server-side socket.on('init',...... will verify the user and can access else return and close the connection.
Never, ever put event handlers like io.on() inside app.get() handlers. That is just wrong and will not do even close to what you want. It will not have an event handler in place until someone hits your page and then every time someone hits that page, it will add a duplicate event handler. Both of these are wrong.
The structure should look like this:
// watch for people hitting the / route in the browser
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
// listen for incoming webSocket connections
io.on('connection', function(socket){
console.log("new connection");
});
This will prevent the duplicate event handlers you were getting.
In case what you were trying to do is to listen for incoming socket.io connections only from a specific page, that is not a support capability. Socket.io connections are from a browser, not from a specific route. You can get access to the cookies associated with the hosting page and the code in the web page making the browser can connect to something like a specific namespace, but there is no built in correlation between an incoming socket.io connection and a specific route the way there is with http requests.
If you're trying to get access to a session object from an incoming socket.io connection, that can usually be done via the cookies associated with the start of the socket.io connection.
I just got my first app up and running on Node.js. As of now, it is simply serving up a static file. But I have a few ideas that will be implemented down the road so I'm going ahead and getting Node setup so I'll be ready for it when that time comes.
// get modules
var express = require('express');
var fs = require('fs');
// create app instance
var app = express();
// static files middleware
app.use("/assets", express.static(__dirname + '/assets'));
// main route
app.get('/', function(req, res) {
var html = fs.readFileSync('assets/views/main.html', 'utf8');
res.send(html);
});
// make web server listen on specific port
app.listen(8080);
NOTE: I realize I don't need Express to serve one route, but I figured what's the harm in getting a head start on that as well?! :)
The first idea i had is to make a way to let all users currently using the app that there has been an update and that they must refresh their browser. There is no need to save the current state of the app as it is pretty basic.
So, if I am a user, I'm using the app and boom, I get a pretty little modal-window-alert-notification thingy letting me know that I need to refresh.
Also, if some user loads the app AFTER I have sent the alert, that user should not see the alert at all (because they should already be seeing the new changes).
I have done some googling on the subject and I'm just not satisfied with the examples i found. I do not think I want to have to update a notifications.xml file (which node.js would be watching) to push a new notification.
One solution I can think of would be to make a command that can be executed from the command line that will (somehow) send a new notification to the app. Perhaps using something like Grunt.js (I'm not sure if it would be a good fit for this as I've never used it). Basically, once the notification has been sent, all traces of it should disappear. That's why I think a command line approach would be good.
Here's my question: How (generally speaking) should I implement something like this? I am a Node.js newbie but I am pretty comfortable with javascript and the command line.
Please feel free to offer up any alternative solution you think would be better for me (other than a command line approach), or any tools that you think could help me.
Thanks!
If you want to push updates to a web client, one way is to use something like Socket.io. This creates a two-way pipe between client and server that you can use to asynchronously push updates through.
Sample server:
var app = require('express').createServer()
, io = require('socket.io').listen(app);
app.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Sample client:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
alert('New news has come in! Please refresh your page!');
socket.emit('my other event', { my: 'data' });
});
</script>
The other option is to poll from the client using Javascript to actively look for updates. You would need to keep some state on the server for each client that would determine if that client required an update. The client would then make a get request on some timer interval (once a second, for example) to a secondary route and the server would reply with 'Yes, you need an update' or 'No, you don't need an update'. If yes, the client Javascript would then pop up your modal box and tell the user to refresh.