Firebase / Node.js, correct usage of on.Disconnect() - node.js

I have a node.js, the monitors a queue on Firebase, to send GCM Push notifications. Works fine.
It also updates an "online" status on firebase via .onDisconnect(), so one can easily see if the Node.js server is online and running.
Problem: after some time it will show "disconnected" even when the listener is still connected and running fine.
const NODESERVERONLINE="NodeSeverStatus";
var ref = new Firebase(FBURL+FBKEY_GCM_QUEUE);
ref.child("NODESERVERONLINE").set("Online");
ref.child("NODESERVERONLINE").onDisconnect().set("Offline!");
ref.on("child_added",function(snapshot, prevChild){
If (snapshot.key()!=NODESERVERONLINE) DO_GCM_PUSH(snapshot.val());
}, function(errorObject){
console.log("Error reading Firebase: " + errorObject.code);
});
Initially, the listener is running and -NodeSeverStatus shows Online.
However "after some time" (several hours), the listener is still running fine, and the queue is being processed, but NodeServerStatus now shows Offline.
I could move the online/offline code inside the listener itself, but that would appear to just be an ugly hack, and would presumably still have the same issue if there were no new queue posts within the timeout period.
What is best practice here? Thankyou.

A quick guess is that your network connection gets interrupted briefly.
If you network connection flaps, the server will detect the disconnect and set Offline!.
The client will automatically reconnect, but you never set Online again.
So you'll want to listen for .info/connected and set Online there.
var ref = new Firebase("https://yours.firebaseio.com");
ref.child("NODESERVERONLINE").onDisconnect().set("Offline!");
ref.child(".info/connected").on("value", function(snapshot) {
if (snapshot.val() === true) {
ref.child("NODESERVERONLINE").set("Online");
}
});
See https://www.firebase.com/docs/web/guide/offline-capabilities.html

Related

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.

Node.js Ignoring blacklisted event 'disconnect' [duplicate]

I have a socket.io connection using xhr as its only transport. When I load up the app in the browser (tested in chrome and ff), the socket connects and everything works well until I navigate away from the page. If I reload the browser, I can see the 'disconnect' event get sent out by the client, but the server disconnect event doesn't fire for a very long time (presumably when the client heartbeat times out). This is a problem because I do some cleanup work in the server when the client disconnects. If the client reloads, I get multiple connection events before disconnect is fired. I've tried manually emitting a disconnect message from the client in the window's 'beforeunload' event as well, but to no avail. Any ideas?
I debugged the socket.io server, and I can confirm that Manager.prototype.onClientDisconnect is only getting hit for "close timeout" reasons.
After some more debugging, I noticed the following configuration in the socket.io Manager object:
blacklist : ['disconnect']
That causes this branch from namespace.js to not process the event:
case 'event':
// check if the emitted event is not blacklisted
if (-~manager.get('blacklist').indexOf(packet.name)) {
this.log.debug('ignoring blacklisted event `' + packet.name + '`');
} else {
var params = [packet.name].concat(packet.args);
if (dataAck) {
params.push(ack);
}
socket.$emit.apply(socket, params);
}
The change is detailed in this pull request https://github.com/LearnBoost/socket.io/pull/569. I understand why this is in place for XHR, since anyone could send an HTTP request with random session IDs trying to disconnect other users from the server.
What I plan to do instead is to check each new connection for an existing session id in the server, and make sure to run my disconnect logic before continuing with the connection logic.

node.js, faye (bayeux) - after subscribe event

I have a chat server. And after the clients subscribes I want to look in a DB to see if there is any history for the chat room they subscribed to.
The problem is, that I can only catch "subscribe" events in extension which must do "return callback(message);" to return the message. If I do the history thingy here nothing gets publishes to the clients because client isn't actually subscribed.
Is there any way to know when client ready? Or some event that happens on successfull subscription?
Thanks!
You can attach a callback after creating the subscription that will fire when you are successfully subscribed and another when you fail to subscribe:
var http = require('http');
var faye = require('faye');
var faye_server = new faye.NodeAdapter({mount: '/faye', timeout: 120});
faye_server.listen(8089);
var subscription = faye_server.getClient().subscribe('/testing', function(message){console.log(message);});
subscription.callback(function(){console.log('Subscription successful and ready to use!');});
subscription.errback(function(){console.log('ERROR: Subscription failed!');});
This is documented on the faye mainpage although it's buried a bit. . . http://faye.jcoglan.com/browser/subscribing.html
This works on a node server, node client, or browser client as I've tested it.
Furthermore, what I have been doing to make sure my clients are up and running is this: create client, then try to subscribe to garbage channel name. Once that subscription comes up, fails, or times out (put 5 second time out around it) I take that as my client open success. It's a bit of a round about method, but it's working very well for me and faye makes it pretty clean by using callback and errback just like in my previous example.
Now that's all on the client side, but it gets much easier on the server side: http://faye.jcoglan.com/node/monitoring.html. Just use the extensions here and look for subscribe events from specific clients and you are good to go.
Hope that helps

NodeJS + Socket.io connections dropping/reconnecting?

In production, I have a game which uses connection-local variables to hold game state. However I notice that if I idle for a certain time on the connection, it disconnects and reconnects which loses the current state. During my tests on a local host, I never noticed this behavior. Is this the norm behavior for socket connections or is something else causing the connections to drop.
If it is a normal behavior how is this typically handled? Should connection values be stored globally so they can be restored should a user drop/reconnect?
Your problem is around socket timeouts. If there's no activity on a certain socket, socket.io will close it automatically.
An easy (and hackish) fix is to send a heartbeat to the connected client to create activity and stop the socket from timing out.
Server:
function sendHeartbeat(){
setTimeout(sendHeartbeat, 8000);
io.sockets.emit('ping', { beat : 1 });
}
io.sockets.on('connection', function (socket) {
socket.on('pong', function(data){
console.log("Pong received from client");
});
}
setTimeout(sendHeartbeat, 8000);
Client:
socket.on('ping', function(data){
socket.emit('pong', {beat: 1});
});
More Information:
You can get more information on configuring socket.io here.
EDIT: Mark commented that if the user does lose the connection (connection drops on his end because of internet troubles), you should be able to restore the user to his last state.
To do that, the best way would be to use a already widely used method for storing user data, cookies and sessions.
An extremely well done tutorial on how to do this located here. Although he uses express to set cookies, you can do this using anything (I do it using rails). Using this method, you can store the user data in a cookie and fetch it during the handshake. From there you can just access the data using socket.handshake.data.
What you need to do is create or identify the session per (re-) connection. You may reduce the number of reconnections per Moox's answer above but it is still not failsafe - e.g. a user loses wifi connection for a bit, etc. In other words - maintain user metadata per session and not per socket, and expect occasional disconnects and reconnects.

Resources