Long polling using node.js to get database updates - mysql

I'm fairly new to Node JS,As I switched from java server pages to node mainly to implement server push technology.
I want to implement a simple application, Which will push the data to users if any new record insertion in Mysql database taken place.
And take database name as wst and table name is registered_people,Table consists of one column named users.
Know if any record is inserted into table it should notify that a new user is added to current users.
How can I achieve that.
Thanks for any help.

This is what libraries like socket.io were designed for. It makes server push operations trivial.
As far as how to actually trigger the server push, that can be more complicated based on how you're getting the data into the database. If all the data into and out of the mysql database goes through the same node application, it's fairly straightforward. Just raise an event when there is an insert into the table, and have your socket.io (or other push code) listen for those events. Then every time a user it added, the message gets sent.
If the database is updated from multiple applications things get a bit more tricky. You can poll the database for updates to the user table, and then fetch the latest users when it changes. You could do something like the following:
setInterval(function() {
getUserCount(function(userCount) {
if(userCount > originalUserCount) {
// We have new users!
// Get the latest user and send it to the connected browsers.
}
});
}, 1000);
This isn't very efficient, but doing a SELECT COUNT(id) FROM Users; shouldn't add much overhead to your database. A cleaner solution would be to use some sort of messaging queue. If you have multiple systems interacting on a single database, a messaging system can ensure that you give all of those systems a chance to subscribe to things that are happening in other parts of the system. In this case you can have your node app subscribe to new user messages in the system and send them to the browsers.

http://socket.io/ is what you are looking for.
As shown in he documentation, its very simple to listen on server using socket.io
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
And connect to it using,
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
You could achieve push by broadcasting the update to all connected clients using io.sockets.emit(object); whenever your database state is changed.
Its also possible to restrict the message to a specific set of clients by using rooms

Related

Best Practice to Safely Migrate Database in SailsJS App when using Mysql

I have an application developed with SailsJS and mysql. Only a logged in user is meant to be able to create a fresh user. During development stage, I made creation of the first user easy with a simple request to server. That is however not feasible again as I have written some policy codes to prevent such.
module.exports= async function(req, res, proceed){
const adminId = req.param('adminId');
if(!adminId){
return res.status(401).json({status: 401, message: 'Unauthorized access, invalid user'});
}
//let's check if the user has a role as superadmin
const superAdmin = await Admin.findOne({id: adminId, superAdmin: true});
console.log(superAdmin)
if(superAdmin){
return proceed();
}
else{
return res.status(401).json({status: 401, message: "Unauthorized access. You don't have this privilege"})
}
}
Also, Every saved new user has a compulsory createdBy column in mysql database.
I currently want to host the project on production. What best way should I do this. By default, I am supposed to run
sails lift --prod
On production environment and generate the mysql tables. However, I won't be able to login or create an admin user. So what is the best way for me to create a new user?
The "best" way is obviously subjective. Personally I would write a migration to bootstrap the DB with the first production user (you are using migrations, right?).
Some people eschew including DML in their migrations, although in my experience at some point in the long lifetime of an application under development, some type of "data fixup" needs to happen. Doing it as idempotently as possible in a migration has been the easiest and most reliable approach.

How can I use socket io for just server client communication?

I would like to build a web page with interactive content.
I would like to use socket IO, but I've got a problem when I send two number from client to the server.
The server adds the two numbers and sends for every user (but I want just send back to the one user). I wouldn't like to store the users. So I would like to ask how can I build this example using NodeJS and Socket IO?
if you look into socket.io docs, you will find out that you can specify the key for each message you send, for instance:
io.on('connection', function (socket) {
// specify a clientId for each client you have, you may define it at the moment the connection starts.
socket.emit(`news:${clientId}`, { hello: 'world' });
});
And, on the client side, you have:
socket.on(`news:${myClientId}`, function (data) {
console.log(data);
});
You may generate this id randomly by using many libraries, for instance Node-Forge.
Hope it helps! Feel free to ask further.

Can I use Feathers for a real-time site that uses data updated from external sources?

In the docs it states that Services only emit events when a Service method modifies data. This is the case in all examples I have seen, where a client modifies that data from the browser itself and it gets automatically updated in other clients (like a chat webapp). But what if my data is modified externally outside of Feathers? Will I be able to use Feathers so that the data is updated in all clients?
In my specific case my data is actually stored in a MongoDB database which gets updated externally and autonomously. I want my web application to use MongoDB Change Streams to listen to changes on the MongoDB database (I already know how to do this) and then I want Feathers to take care of sending updates to all my clients in real-time.
In the example chat app, this would be equivalent to having a bot that also writes messages directly to the database outside of Feathers, and this messages should also be broadcasted to clients in real-time.
Is my use-case a good fit for Feathers? Any hint on how should I approach it?
Watching changefeeds has been done for feathers-rethinkdb here. Something similar could be done for MongoDB but there are several challenges discussed in this issue.
If your MongoDB collection only gets updated externally you could also create a simple pass through service like this:
app.use('/feed/messages', {
async create(data) {
return data;
},
async remove(id) {
return { id };
},
async update(id, data) {
return data;
},
async patch(id, data) {
return data;
}
});
Which is then called by the changefeed watcher and will automatically take care of updating all the clients through its events.

How to make a nodejs server asynchronous

I have a nodeJS server, that takes JSON from three websites and sends it to be displayed on my website(in JSON). The JSON on the websites that I'm taking from is constantly updated, every 10 seconds. How can I make my NodeJS server constantly update so it has the most up to date data?
I'm assuming this isn't possible without refreshing the page, but it would be optimal if the page wasn't refreshed.
If this is impossible to do with NodeJS and there is a different method of accomplishing this, I would be extremely appreciative if you told me.
Code:
router.get("/", function(req, res){
var request = require('request-promise');
var data1;
var data2;
var data3;
request("website1.json").then(function(body){
data1 = JSON.parse(body);
return request("website2.json");
})
.then(function(body) {
data2 = JSON.parse(body);
return request("website3.json");
})
.then(function(body){
data3 = JSON.parse(body);
res.render("app.ejs", {data1: data1, data2: data2, data3: data3});
})
});
Here's some general guidelines:
Examine the APIs you have available from your external service. Find out if there is anything it offers that lets you make a webSocket connection or some other continuous TCP connection so you can get realtime (or close to realtime) notifications when things change. If so, have your server use that.
If there is no realtime notification API from the external server, then you are just going to have to poll it every xx seconds. To decide how often you should poll it, you need to consider: a) How often you really need new data in your web pages (for example, maybe data that is current within 5 minutes is OK), b) What the terms of service and rate limiting are for the 3rd party service (e.g. how often will they let you poll it) and c) how much your server can afford to poll it (from a server load point of view).
Once you figure out how often you're going to poll the external service, then you build yourself a recurring polling mechanism. The simplest way would be using setInterval() that is set for your polling interval time. I have a raspberry pi node.js server that uses a setInterval() to repeatedly check several temperature sensors. That mechanism works fine as long as you pick an appropriate interval time for your situation.
Then for communication of new information back to a connected web page, the best way to get near "real time" updates form the server is for the web page to make a webSocket or socket.io connection to your server. This is a continuously connected socket over which messages can be sent either way. So, using this mechanism, the client makes a socket.io connection to your server. The server receives that connection and the connection stays open for the lifetime of that web page. Then, anytime your server has new data that needs to be sent to that web page, it can just send a message over that socket.io connection. The web page will receive that message and can then update the contents of the web page accordingly based on the data in the message. No page refresh is needed.
Here's an outline of the server code:
// start up socket.io listener using your existing web server
var io = require('socket.io')(app);
// recurring interval to poll several external web sites.
setInterval(function () {
var results = {};
request("website1.json").then(function (body) {
results.data1 = JSON.parse(body);
return request("website2.json");
}).then(function (body) {
results.data2 = JSON.parse(body);
return request("website3.json");
}).then(function (body) {
results.data3 = JSON.parse(body);
// decide if anything has actually changed on external service data
// and whether anything needs to be sent to connected clients
io.emit("newData", results);
}).catch(function(err) {
// decide what to do if external service causes an error
});
}, 10000);
The client code would then be generally like this:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on("newData", function(data) {
// process new data here and update the web page
});
</script>

Keeping a user logged in with nodeJS

I have a login system with my NodeJS using mysql-node.
The problem i have how ever is how to keep the user logged in, if they refresh the page they have to login again, because i do not know how to store the session.
My login system is like this:
socket.on('login', function(data,callBack){
var username = sanitize(data['login']).escape(),
pass = sanitize(data['password']).escape();
var query = connection.query('SELECT uid FROM users WHERE name = ? AND pass = ?', [username,pass],
function(err,results){
if(err){
console.log('Oh No! '+err);
} else if(results.length == 1){
//some how set a session here
} else if(!results.length) {
console.log('No rows found!');
}
});
});
I'm having difficulty understanding how i set up a session for each client that connects. Is this possible with NodeJS ?
Reading that they assign express to var app but if i already have this : var app = http.createServer( ... how can i also assign express to it :S bit confusing
You need to understand the difference between a express' server and a native NodeJS' server, here my link comparaison nodejs server vs express server
So you can do:
var app = express();
var server = http.createServer(app);
This enable you to have still the low level functionnaly with NodeJS.
So, if you don't want to use existing modules or framework, you can build your own session manager:
using cookie
using IP/UA
using socket
The best way would be first to implement it with socket, for example:
server.on('connection', function (socket) {
socket.id = id;
});
or
server.on('request', function (req, res) {
req.connection.id = id; // The socket can also be accessed at request.connection.
});
So, you just need to implement a middleware who check the id.
If you want to prevent from session prediction, session sidejacking, etc. you need to combine cookies, ip, socket, and your ideas to make it more secure for your app.
Once you've done your session manager, you can choose where to store the sessions, in a simple object, in redis, in mongodb, in mysql ... (express use MemoryStore by default, but maybe not now)
I don't have an idea if nodejs has core feature of saving sessions. you need to use a database along with it. using Express will help you to utilized a database to persist user sessions. You better study and use it
http://expressjs.com/
http://blog.modulus.io/nodejs-and-express-sessions
I don't think there is any session mechanism within Nodejs' core. However, they are plenty of libraries that would allow you to do it. The first that comes to mind is Connect's session, which is a middleware for Nodejs. Have a look at this question for more details on how to use it.
Have a look at this tutorial from dailyjs which tries to include Express's session into a notepad webapp. The source code is available here. (Note that Express' session is based on Connect's, and is practically the same).
EDIT: Here is a more complete example for Node authentication, using mongoose. They do however show their schemas, so I assume you can easily do the transition to MySQL.