Streaming html5 animation in real time from server to client - node.js

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();
});

Related

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)

Why isn't my simple socket.io event system working?

I am running into a problem while using socket.io to do some event handling. For some reason, the following code snippet does not handle the event 'update', or any event for that matter. Let me explain the situation.
I have created a file named updates.js to create a socket.io socket variable named socket_8888 that is bound to port 8888. I then use module.exports to make that socket variable available to any other file that imports updates.js using require('updates.js'). I structured my application this way because I need to emit events from several different files.
In app.js:
var updates = require('updates.js');
setTimeout(function() {
updates.regular.on("update", function () {
console.log("Updated.");
})
}, 1000);
setTimeout(
function () {
console.log(updates.regular.eventNames()); // Verifying that there is actually a listener bound to the socket -> prints ['update']
updates.regular.emit("update", 100)
}, 1500);
In updates.js:
var io = require("socket.io");
var socket_8888 = io(8888);
var updates = {
regular: socket_8888
};
module.exports = updates;
However, a few simple tests have uncovered that events are not being handled, and I really cannot figure out why. The word "Updated" should print a second and a half after I run the application using "node www", but it does not.
The reason I started doing this simple testing was because I am trying to revive an old website of mine, but after a couple years, API updates have rendered a lot of my code useless. So I am trying to rebuild. I am not trying to send events between different files on the server. I am only testing the events locally because the events were not firing to the browser client. For this reason, I decided to investigate using this simple test, and it turns out the events can not even be emitted/listened to on the actual server, let alone be handled on a client that is on a whole different network.
I have already verified that the listener is actually binding to the socket. However, I do not know how to check whether or not the socket is actually emitting the event "update".
I have written the listener to bind only after one second because attempting to bind the moment the application starts does not give Express enough time to set everything up. Otherwise, the socket would still be undefined.
I do not get any error messages. The code just does not work as I expected.
I would really appreciate it if the community can tell me why the event 'update' is not being handled.
To include update module (update.js)
Try this
It work's Perfectly
module.exports = updates
var updates = require('./updates');

How to catch when a user leaves the page in Meteor and/or Iron router?

I'm trying to catch when a user leaves from my Meteor application (version 1.2.0.2) ; something equivalent to the SocketIO disconnect() on the server side.
The user could close his browser, go to another website or simply refresh the page and it would fire anyway
Surprisingly, i'm searching on Internet and everything is mixed up, nothing works properly. I thought Meteor was literally based on this magic-live processing so it must manage this event in a way or another.
Iron router documentation specify this :
onStop: Called when the route is stopped, typically right before a new
route is run.
I also found Router.load and Router.unload but none of them work. This is my current [not working] code which is quite simple
Router.configure
layoutTemplate: 'MasterLayout'
loadingTemplate: 'Loading'
notFoundTemplate: 'NotFound'
Router.onStop (->
console.log('Try to stop')
Users.insert({
name: "This is a test"
lat: 0
lng: 0
})
)
Am I doing something wrong here ? How do you catch this event in my app ?
You need to attach to the onStop of the route, not the router. For instance:
Router.route('/', {
onStop: function() {
console.log("someone left the '/' route");
}
});
Another option is to use the onStop event of subscriptions. That is probably the option most similar to the socketio disconnect you mentioned. You can find an example of that in the typhone source code.
There were two solution working, I found the 2nd and best one by searching in the API Documentation for a while.
First solution : working with subscribe & publish
Anywhere in the controller / front-end side you must subscribe to a collection
# in coffee
#subscribe('allTargets')
# in javascript
this.subscribe('allTargets')
Afterwards you just have to publish and add a onStop listener. This example will take a Targets collection I already defined somewhere before, it just gets all the entries.
# in coffee
Meteor.publish 'allTargets', ->
#onStop ->
# Do your stuff here
return Targets.find()
# in javascript
Meteor.publish('allTargets', function() {
this.onStop(function() {
// Do your stuff here
});
return Targets.find();
});
You have to be careful not to return Targets.find() before you set the onStop listener too. I don't think it's a perfect solution since you don't listen to the connection itself but the changes of a collection.
Second solution : working with DDP connection
I realized through the Meteor API Documentation we can directly listen to the connection and see if someone disconnect from the server-side.
To stay well-organized and clean within my Meteor Iron project I added a new file in app/server/connection.coffee and wrote this code
# in coffee
Meteor.onConnection (connection) ->
connection.onClose ->
# Do your stuff
# in javascript
Meteor.onConnection(function(connection) {
connection.onClose(function() {
// Do your stuff
});
});
You can manage datas with connection.id which's the unique identifier of your browser tab. Both solutions are working well for me.
If you use Meteor.userId through their accounts system, you can't use it outside a method in the server-side so I had to find a workaround with the connection.id.
If anyone has a better solution to manage connections while getting this kind of client datas, don't hesitate to give your input.

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

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)

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