How to use node.js in a real time gps tracking application? - node.js

I am trying to understand how node.js will fit in my scenario.
Currently, a mobile device sends gps coordinates to a Rails backend thru POST. The mobile device sends it every minute.
POST http://127.0.0.1:3000/location/
My RubyOnRails web app can display the history of locations on a map, no problem with this.
But my experience in nodejs is still in its infancy and I would like to understand how to display a map for real time GPS updates as they come in.

Use Socket.IO.
Most tutorials show some kind of chat application. In your case the communication is only uni-directional. And your device is not connected through WebSockets, but only POSTs new coordinates without a channel back (device doesn't subscribe to events from server).
Your web-page (showing a Google Maps control) connects to your Node.js server through socket.io and gets new coordinates pushed from your server (socket.emit). You have to remember somehow which "new-coordinate" events from devices have to be published to which listening web-clients.
And of course you need an initial list of recent coordinates for your web-page if you want to show not only new coordinates of a device. You could deliver them over sockets as well, but as you will need some kind of authentication maybe a REST call is clearer for first population of devices GPS-track.
So when a device updates its location, you only have to find connected listeners for that device and emit("new-coordinate", {lat: ..., lng: ..., deviceId: ...} events to the maps. In the web-page, you receive the events and handle them like this:
<script src="/socket.io/socket.io.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
if (typeof io === 'undefined') {
return; // socket.io not loaded
}
var socket = io.connect();
socket.on('new-coordinate', function (data) {
console.log('arrived', data);
$(document).trigger('new-coordinate', data);
// or just directly update your map ...
});
});
</script>
Edit
As your web-page and the new-coordinate POSTs are delivered through RoR, you have to trigger the events from Ruby to node.js server-side. Basically you could call your node.js app from Ruby via REST, but there are other options like Redis pub/sub or dnode ruby.
(comment) I'd migrate the RoR app to node.js ;-) (/comment)

Related

Streaming html5 animation in real time from server to client

I have an animation written in Javascript. I am new to nodejs (no knowledge) and I have been finding it difficult to stream the animation in real-time to users connected to the site.
I read about socket.io and Websockets but I do not have a good approach. Currently, the animation starts with a function call and writes to a canvas.
I need to know how to stream this animation from the server-side to the client so that multiple connected users can see the same scene of the animation at the same time. A functional explanation with code will also be appreciated.
Without knowing what type of animations are used, how they're built and work, I would suggest doing the animation client-side and just send some sort of synchronization command from server to all clients using socket.io .
I also would suggest putting all users (which all should see the same animation) in to one room (see rooms).
Now you can send a synchronized command to all users, e.g. to start, continue, stop and reset the animation. On the other hand, on the server-side you could track which of the clients in the room have already loaded the animation, started, stopped and so on.
// server
io.to('some-room').emit('load', animationid);
/* ... */
socket.on('loaded', () => {
if (allClientsLoaded) {
io.to('some-room').emit('start');
}
});
socket.on('started', () => {
});
// client
socket.on('load', async (animationid) => {
await loadAnimation(animationid);
socket.emit('loaded');
});
socket.on('start', () => {
startAnimation();
});

Is there a better solution than socket.io for slow-speed in-game chat?

I am creating a browser game with node.js (backend api) and angular (frontend). My goal is to implement an in-game chat to allow communication between players on the same map. The chat is not an essential part of the game, so messages don't need to be instant (few seconds of latency should be ok). It is just a cool feature to talk some times together.
A good solution should be to implement socket.io to have real-time communication. But as chat is not an essential component and is the only thing which will require websockets, i'm wondering if there is not an alternative to avoid server overload with sockets handling.
I thinked about polling every 2 or 3 seconds my REST API to ask for new messages, but it may overload server the same way... What are your recommandations?
Thank you for your advices
There's a pretty cool package called signalhub. It has a nodejs server component and stuff you can use in your users' browsers. It uses a not-so-well-known application of the http (https) protocol called EventSource. EventSource basically opens persistent http (https) connections to a web server.
It's a reliable and lightweight setup. (The README talks about WebRTC signalling, but it's useful for much more than that.)
On the server side, a simple but effective server setup might look like this:
module.exports = function makeHubServer (port) {
const signalhubServer = require('signalhub/server')
const hub = signalhubServer({ maxBroadcasts: 0 })
hub.on('subscribe', function (channel) {
/* you can, but don't have to, keep track of subscriptions here. */
})
hub.on('publish', function (channel, message) {
/* you can, but don't have to, keep track of messages here. */
})
hub.listen(port, null, function () {
const addr = hub.address()
})
return hub
}
In a browser you can do this sort of thing. It user GET to open a persistent EventSource to receive messages. And, when it's time to send a message, it POSTs it.
And, Chromium's devtools Network tab knows all about EventSource connections.
const hub = signalhub('appname', [hubUrl])
...
/* to receive */
hub.subscribe('a-channel-name')
.on('data', message => {
/* Here's a payload */
console.log (message)
})
...
/* to send */
hub.broadcast('a-channel-name', message)

I can't get my head around websockets (via socket.io and node.js)

I'm new to websockets/socket.io/node.js. I'm trying to write a card game app, but pretty much all the example tutorials I've found are creating chat applications. So I'm struggling to get my head around the concepts and how they can be applied to my card game.
Keeping it simple, the card game will involve two players. The game involves moving cards around the table. Each player has to see the other player's moves as they happen (hence the need for constant connections). But the opponents cards are concealed to the other.
So two people browse to the same table then click to sit (and play, when both seats are taken). Using
io.on("connection", function(sock){
//socket events in here
});
am I creating the one socket ('io', or 'sock'?) that both clients and the server share, or is that two separate sockets (server/clientA and sever/clientB)? I ask, because I'm struggling to understand what's happening when a message is emitted and/or broadcast. If a client emits a message, is that message sent to both the server and the other client, or just the server? And then, further does it also send the message to itself as well?? It seems as though that's the logic... or what is the purpose of the 'broadcast' method?
From a functional perspective, I need the server to send different messages to each player. So it's not like a chatroom where the server sends the chat to everyone. But if it's one socket that the three of us share (clients and server), how do I manage who sees what? I've read about namespaces, but I'm struggling to work out how that could be used. And if it's two separate sockets, then I can more easily imagine sending different data to the separate clients. But how is that implemented - is that two 'io' objects, or two 'sock' objects?
Finally, I've got no idea if this is the sort of long-winded question that is accepted here, so if it's not, can someone direct me to a forum that discussions can occur? Cheers!
(in case it matters I'm also using Expressjs as the server).
Edit to add:
Part of my confusion is regarding the difference between 'io' and 'sock'. This code eg from the socket.io page is a good example of methods being applied to either of them:
io.on('connection', function(socket){
socket.emit('request', /* */); // emit an event to the socket
io.emit('broadcast', /* */); // emit an event to all connected sockets
socket.on('reply', function(){ /* */ }); // listen to the event
});
WebSocket server side listens for incoming socket connections from clients.
Each client upon connection opens its own socket between him and server. The server is the one that keeps track of all clients.
So once client emits the message server is listening for, the server can do with that message whatever. The message itself can contain information about who is the recipient of that message.
The server can pass the message to everyone or broadcast it to specific user or users based on information your client has sent you or some other logic.
For a card game:
The server listens for incoming connections. Once two clients are connected both of them should emit game ID in which they want to participate. The server can join their sockets in one game(Room) and all of the communication between those two clients can continue in that room. Each time one of the clients passes data to the server, that data should contain info about the recipient.
Here is one simple example that could maybe get you going:
Client side
// set-up a connection between the client and the server
var socket = io.connect();
// get some game identifier
var game = "thebestgameever";
socket.on('connect', function() {
// Let server know which game you want to play
socket.emit('game', game);
});
function makeAMove(move)
{
socket.emit('madeAMove', {move:move, game:game});
}
socket.on('move', function(data) {
console.log('Player made a move', data);
});
Server side
io = socketio.listen(server);
//listen for new connections from clients
io.sockets.on('connection', function(socket) {
// if client joined game get his socket assigned to the game
socket.on('game', function(game) {
socket.join(game);
});
socket.on('madeAMove', function(data){
let game = data.game;
let move = data.move;
io.sockets.in(game).emit('move', move);
});
})

How to automate API get data request? when using web sockets

As far as I know Web Sockets allows bi-directional communication. and web sockets (for example: Socket.io) connections are always open. so, whenever new data has arrived data should be automatically pushed to the view via socket.
but in below code I am using set_interval to make a http.get call. and set_interval is called once every 1 second.
now, doing these does not give a real-time feel that is, the new data is pulled once every 1 second. which is statically defined.
in-short, I want to automate what set_interval does in below code. I don't want a static fetch interval value. This is because at-times stock price could change within 100ms and at times it would change once in few seconds.
Now, if I set interval to 1 sec, that is make a call every 1 second. the real feel of high fluctuation in market move would not be seen.
I am not sure how usually developers fetch data in IOT applications. for example car is monitored in real-time and let's say speed of the car is fetched in real time and graphed on a web or mobile application.
How do I achieve something similar like that in Stock Ticker? I want to simply plugin the application to an API and when new data arrives instantly push it to all the viewers (subscribers) in real-time.
Code below
////
// CONFIGURATION SETTINGS
////
var FETCH_INTERVAL = 1000;
var PRETTY_PRINT_JSON = true;
////
// START
////
var express = require('express');
var http = require('http');
var https = require('https');
var io = require('socket.io');
var cors = require('cors');
function getQuote(socket, ticker) {
https.get({
port: 443,
method: 'GET',
hostname: 'www.google.com',
path: '/finance/info?client=ig&q=' + ticker,
timeout: 1000
}, function(response) {
response.setEncoding('utf8');
var data = '';
response.on('data', function(chunk) {
data += chunk;
});
response.on('end', function() {
if(data.length > 0) {
var dataObj;
try {
dataObj = JSON.parse(data.substring(3));
} catch(e) {
return false;
}
socket.emit(ticker, dataObj[0].l_cur);
}
});
});
}
I am making a call to method getQuote depending on FETCH_INTERVAL set above
function trackTicker(socket, ticker) {
// run the first time immediately
getQuote(socket, ticker);
// every N seconds
var timer = setInterval(function() {
getQuote(socket, ticker);
}, FETCH_INTERVAL);
socket.on('disconnect', function () {
clearInterval(timer);
});
}
var app = express();
app.use(cors());
var server = http.createServer(app);
var io = io.listen(server);
io.set('origins', '*:*');
app.get('/', function(req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket) {
socket.on('ticker', function(ticker) {
trackTicker(socket, ticker);
});
});
server.listen(process.env.PORT || 4000);
Edits - Update
Okay, so I would need real-time feed. (this bit is sorted)
As far as I know, Real-time feeds are quite expensive and buying 10,000+ end points for each online client is quite expensive.
1) How do I make use of real-time feed to serve 1000s of end users? Can I use web sockets, Redis, publish/subscribe, broadcasting or some technology that copies real-time feed to tonnes of users? I want a efficient solution because I want to keep the expense of real-time data feed as low as possible.
How do I tackle that issue?
2) Yes, I understand polling needs to be done on server side and not on a client-side (to avoid doing polling for each client). but then what tech do I need to use? websockets, redis, pub/sub etc..
I have API URL and a token to access the API.
3) I am not just in need to fetch the data and push it to end users. But I would need to do some computation on the fetched data, will need to pull data from Redis or database as well and do calculations on it then push it to the view.
for example:
1) data I get in real-time market feed {"a":10, "b":20}
2) get data from DB or Redis {"x":2, "y":4}
3) do computation : z = a * x + b * y
4) finally push value of z in the view.
How do I do all these in real-time at the same-time push it to multiple clients?
Can you share a roadmap with me? I got the first piece of the puzzle getting real-time datafeed.
1) How do I make use of real-time feed to serve 1000s of end users? Can I use web sockets, Redis, publish/subscribe, broadcasting or some technology that copies real-time feed to tonnes of users? I want a efficient solution because I want to keep the expense of real-time data feed as low as possible.
How do I tackle that issue?
To "push" data to browser clients, you would want to use a webSocket or socket.io (built on top of webSockets). Then, anytime your server knows there's an update, it can immediately send that update to any currently connected client that is interested in that info. The basic idea is that the client connects to your server as soon as the web page is loaded and keeps that connection open for as long as the web page(s) are open.
2) Yes, I understand polling needs to be done on server side and not on a client-side (to avoid doing polling for each client). but then what tech do I need to use? websockets, redis, pub/sub etc..
It isn't clear to me what exactly you're asking about here. You will get updated prices using whatever the most efficient technology is that is offered by your provider. If all they provide is http calls, then you have to poll regularly using http requests. If they provide a webSocket interface to get updates, then that would be preferable.
There are lots of choices for how to keep track of which clients are interested in which pieces of information and how to distribute the updates. For a single server, you could easily build your own with just a Map of stock prices where the stock symbol is the key and an array of client identifiers is the value in the Map. Then, any time you get an update for a given stock, you just fetch the list of client IDs that are interested in that stock and send the update to them (over their webSocket/socket.io connection).
This is also a natural pub/sub type of application so anyone of the backends that support pub/sub would work just fine too. You could even use an EventEmitter where you .emit(stock, price) and each separate connection adds a listener for the stock symbols they are interested in.
For multiple servers at scale, you'd probably want to use some external process that manages the pub/sub process. Redis is a candidate for that.
3) I am not just in need to fetch the data and push it to end users. But I would need to do some computation on the fetched data, will need to pull data from Redis or database as well and do calculations on it then push it to the view.
I don't really see what question there is here. Pick your favorite database to store the info you need to fetch so you can get it upon demand.
How do I do all these in real-time at the same-time push it to multiple clients? Can you share a roadmap with me? I got the first piece of the puzzle getting real-time datafeed.
Real-time data feed.
Database to store your meta data used for calculations.
Some pub/sub system, either home built or from a pre-built package.
Then, follow this sequence of events.
Client signs in, connects a webSocket or socket.io connection.
Server accepts client connection and assigns a clientID and keeps track of the connection in some sort of Map between clientID and webSocket/socket.io connection. FYI, socket.io does this automatically for you.
Client tells server which items it wants to monitor (probably message sent over webSocket/socket.io connection.
Server registers that interest in pub/sub system (essentially subscribing the client to each item it wants to monitor.
Other clients do the same thing.
Each time client requests data on a specific item, the server makes sure that it is getting updates for that item (however the server gets its updates).
Server gets new info for some item that one or more clients is interested in.
New data is sent to pub/sub system and pub/sub system broadcasts that information to those clients that were interested in info on that particular item. The details of how that works depend upon what pub/sub system you choose and how it notifies subscribers of a change, but eventually a message is sent over webSocket/socket.io for the item that has changed.
When a client disconnects, their pub/sub subscriptions are "unsubscribed".

Multiplayer HTML5 semi-real-time game, node.js/socket.io

I would like to create a multiplayer HTML5 semi-real-time game using node.js and socket.io. The frame rate is 3 fps. Players use the arrow keys to move. All game objects move in straight lines (players move horizontally or vertically). Players press Page Up/Down to speed up/slow down. This is my first animated HTML5 game, and my first heavy duty JavaScript project.
I went through a tutorial called "Creating a real-time multiplayer game with WebSockets and Node.js" (click here). This tutorial displays a black square for each player with arrow key movement. Unfortunately it only works on one computer (but multiple browser tabs). You have to point your browser(s) to the public/index.html file. I would like to modify it so I can join in the game from the other computer on my LAN, by pointing my browser to 192.168.1.4:8000. Eventually I would like my brother to join in by visiting myquadrawebsite.com. I know how to do port forwarding for apache but not node.js. Here are 3 snippets of abridged, high-level code from the tutorial:
// public/index.html
<script src="http://localhost:8000/socket.io/socket.io.js"></script>
<script src="js/game.js"></script>
<script> // Initialise the game
init();
animate();
</script>
// game.js
var io = require("socket.io");
var socket, players;
function init() {
players = [];
socket = io.listen(8000);
setEventHandlers();
};
var setEventHandlers = function() {
socket.sockets.on("connection", onSocketConnection);
};
function onSocketConnection(client) {
util.log("New player has connected: "+client.id);
client.on("new player", onNewPlayer);
};
// public/js/game.js
var remotePlayers, localPlayer, socket;
function init() {
localPlayer = new Player(startX, startY);
socket = io.connect("http://localhost", {port: 8000, transports: ["websocket"]});
remotePlayers = [];
setEventHandlers();
};
var setEventHandlers = function() {
socket.on("connect", onSocketConnected);
socket.on("new player", onNewPlayer);
};
I have searched high and low for other tutorials about node.js and socket.io, but none of them have helped me so far. (My long term goal is to create an HTML5 game development framework.) If anyone can possibly point me in the right direction, I'd appreciate it. Thanks.
Unfortunately it only works on one computer (but multiple browser tabs)
This strongly suggests that you are running the server on one computer and it is not accessible from the other computer clients (the web browsers).
You should ensure that the code you use in the client uses a URL that is accessible by anybody (any client) trying to access the game e.g.
socket = io.connect("http://localhost", {port: 8000, transports: ["websocket"]});
Definitely won't work for anybody other than the person on the computer running the server.
If you update the URL to 192.168.1.4:8000 and that address is accessible to others then it is much more likely to work.
you shouldn't have to point your browser to the public, the address (depending on where you routed it (if your using express it'll just be /index.html)) http://127.0.0.1:8000 (equivalent to localhost) http://127.0.0.1:8000/index.html
I'm about halfway through my first socket.io game and i'd definitely suggest using a service like nodejitsu for deploying or even testing your game

Resources