ws.onclose event does not get called on nodejs exit - node.js

i use web sockets and the onclose method does not get triggert when the server is down.
i tried to close the ws connections manually with progress.exit but it seems this only gets triggert on a clean exit.
is their a way to catch a stopped nodejs app and execute code before the stop?
it should trigger on ctr+c and any other crash/exit.
basicly i want to tell the client when the connection is not alive anymore before he is trying to do something, since onclose does not handel every case, what can i do to check the connection?
the only solution i came up with is to ping the server from time to time.

since this is not possible i started sending pings as a workarround:
var pingAnswer = true;
pingInterval = setInterval(function(){
if(pingAnswer){
ws.send(JSON.stringify({type:'ping'})); //on the serverside i just send a ping back everytime i recive one.
pingAnswer = false;
}else{
clearInterval(pingInterval);
//reload page or something
}
},1000);
ws.onMessage(function(e){
m = JSON.parse(e.data);
switch(m.type){
....
case 'ping':
pingAnswer=true;
return;
}
}
);

You don't provide a snippet showing how you're defining your on('close',...) handler, but it's possible that you're defining the handler incorrectly.
At the time of this writing, the documentation for websocket.onclose led me to first implement the handler as ws_connection.onclose( () => {...});, but I've found the proper way to be ws_connection.on('close', () => {...} );
Maybe the style used in the ws documentation is some kind of idiom I'm unfamiliar with.
I've tested this with node 6.2.1 and ws 1.1.1. The on.('close',...) callback is triggered on either side (server/client) when the corresponding side is shutdown via Ctrl+c or crashes for whatever reason (for example, for testing, JSON.parse("fail"); or throw new Error('');).

Related

How can I get who paused the video in Youtube API? (with Socket.io)

Basically, I'm challenging myself to build something similar to watch2gether, where you can watch youtube videos simultaneously through the Youtube API and Socket.io.
My problem is that there's no way to check if the video has been paused other than utilizing the 'onStateChange' event of the Youtube API.
But since I cannot listen to the CLICK itself rather than the actual pause EVENT, when I emit a pause command and broadcast it via socket, when the player pauses in other sockets, it will fire the event again, and thus I'm not able to track who clicked pause first NOR prevent the pauses from looping.
This is what I currently have:
// CLIENT SIDE
// onStateChange event
function YtStateChange(event) {
if(event.data == YT.PlayerState.PAUSED) {
socket.emit('pausevideo', $user); // I'm passing the current user for future implementations
}
// (...) other states
}
// SERVER SIDE
socket.on('pausevideo', user => {
io.emit('smsg', `${user} paused the video`)
socket.broadcast.emit('pausevideo'); // Here I'm using broadcast to send the pause to all sockets beside the one who first clicked pause, since it already paused from interacting with the iframe
});
// CLIENT SIDE
socket.on('pausevideo', () => {
ytplayer.pauseVideo(); // The problem here is, once it pauses the video, onStateChange obviously fires again and results in an infinite ammount of pauses (as long as theres more than one user in the room)
});
The only possible solution I've thought of is to use a different PLAY/PAUSE button other than the actual Youtube player on the iframe to catch the click events and from there pause the player, but I know countless websites that uses the plain iframe and catch these kind of events, but I couldn't find a way to do it with my current knowledge.
If the goal here is to be able to ignore a YT.PlayerState.PAUSED event when it is specifically caused by you earlier calling ytplayer.pauseVideo(), then you can do that by recording a timestamp when you call ytplayer.pauseVideo() and then checking that timestamp when you get a YT.PlayerState.PAUSED event to see if that paused event was occurring because you just called ytplayer.pauseVideo().
The general concept is like this:
let pauseTime = 0;
const kPauseIgnoreTime = 250; // experiment with what this value should be
// CLIENT SIDE
// onStateChange event
function YtStateChange(event) {
if(event.data == YT.PlayerState.PAUSED) {
// only send pausevideo message if this pause wasn't caused by
// our own call to .pauseVideo()
if (Date.now() - pauseTime > kPauseIgnoreTime) {
socket.emit('pausevideo', $user); // I'm passing the current user for future implementations
}
}
// (...) other states
}
// CLIENT SIDE
socket.on('pausevideo', () => {
pauseTime = Date.now();
ytplayer.pauseVideo();
});
If you have more than one of these in your page, then (rather than a variable like this) you can store the pauseTime on a relevant DOM element related to which player the event is associated with.
You can do some experimentation to see what value is best for kPauseIgnoreTime. It needs to be large enough so that any YT.PlayerState.PAUSED event cause by you specifically calling ytplayer.pauseVideo() is detected, but not so long that it catches a case where someone might be pausing, then unpausing relatively soon after.
I actually found a solution while working around what that guy answered, I'm gonna be posting it in here in case anyone gets stuck with the same problem and ends up here.
Since socket.broadcast.emit doesn't emit to itself, I created a bool ignorePause and made it to be true only when the client received the pause request.
Then I only emit the socket if the pause request wasn't already broadcasted and thus received, and if so, the emit is ignored and the bool is set to false again in case this client/socket pauses the video afterwards.

How to add continuous running code into nodejs postgresql client?

I'm stuck on a problem of wiring some logic into a nodejs pg client, the main logic has two part, the first one is connect to postgres server and getting some notification, it is as the following:
var rules = {} // a rules object we are monitoring...
const pg_cli = new Client({
....
})
pg_cli.connect()
pg_cli.query('LISTEN zone_rules') // listen to the zone_rules channel
pg_cli.on('notification', msg => {
rules = msg.payload
})
This part is easy and run without any issue, now what I'm trying to implement is to have another function keeps monitoring the rules, and when an object is received and put into the rules, the function start accumulating the time the object stays in the rules (which may be deleted with another notification from pg server), and the monitoring function would send alert to another server if the duration of the object passed a certain time. I tried to wrote the code in the following style:
function check() {
// watch and time accumulating code...
process.nextTick(check)
}
check()
But I found the onevent code of getting notification then didn't have a chance to run! Does anybody have any idea about my problem. Or should I doing it in another way?
Thanks!!!
Well, I found change the nextTick to setImmediate solve the problem.

How can I simulate latency in Socket.io?

Currently, I'm testing my Node.js, Socket.io server on localhost and on devices connected to my router.
For testing purposes, I would like to simulate a delay in sending messages, so I know what it'll be like for users around the world.
Is there any effective way of doing this?
If it's the messages you send from the server that you want to delay, you can override the .emit() method on each new connection with one that adds a short delay. Here's one way of doing that on the server:
io.on('connection', function(socket) {
console.log("socket connected: ", socket.id);
// override the .emit() method
const emitFn = socket.emit
socket.emit = (...args) => setTimeout(() => {
emitFn.apply(socket, args)
}, 1000)
// rest of your connection handler here
});
Note, there is one caveat with this. If you pass an object or an array as the data for socket.emit(), you will see that this code does not make a copy of that data so the data will not be actually used until the data is sent (1 second from now). So, if the code doing the sending actually modifies that data before it is sent one second from now, that would likely create a problem. This could be fixed by making a copy of the incoming data, but I did not add that complexity here as it would not always be needed since it depends upon how the caller's code works.
An old but still popular question. :)
You can use either "iptables" or "tc" to simulate delays/dropped-packets. See the man page for "iptables" and look for 'statistic'. I suggest you make sure to specify the port or your ssh session will get affected.
Here are some good examples for "tc":
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem

Why "close" event when something goes wrong with node-amqp?

(I am using node-amqp and rabbitmq server.)
I am trying to guess why I have a close event if something goes wrong. For example, If I try to open a a connection to a queue (with bad parameters) I receive an error event. That it is perfect ok.
But, after any error I will receive also a close connection (in that case, maybe because close the failed socket to the queue). And after that, auto-reconnect and I receive the (initial) ready event.
The problem:
connection.on('ready', function() {
do_a_lot_of_things
}).on(error, function(error){
solve_the_problem
});
if something goes wrong, I receive the error, but then "ready" event and it will re do_a_lot_of_things. Is my approach wrong?
best regards
You can use connection.once('ready', function () { … }) (see the documentation), which will execute the handler only on the first event.

Networking without blocking ui in Qt 4.7

I have a server to which multiple clients can connect to. The client is GUI while the server is command line. The client has several functions (such as connect and login) which, when sent to the server should receive a reply.
Basically I need to run the QTcpSocket functions waitForConnection and waitForReadyRead. However, I need to do this without blocking the UI.
What I thought of doing was the following:
Have a class (Client) implement QThread which does all the waiting. This is created in main.
Client::Client (...)
{
moveToThread (this); // Not too sure what this does
mClient = new QTcpSocket (this);
start();
}
void Client::run (void)
{
exec();
}
void Client::connectToServer (...)
{
mClient->connectToHost (hostname, port);
bool status = mClient->waitForConnected (TIMEOUT);
emit connected (status);
}
void Client::login (...)
{
... Similar to connectToServer ...
}
Then the GUI (for example, ConnectToServerDialog) I run this whenever I am ready to make a connection. I connect the "connected signal" from the thread to the dialog so when I am connected or connection timed out it will emit this signal.
QMetaObject::invokeMethod (mClient, "connectToServer", Qt::QueuedConnection,
Q_ARG (const QString &, hostname), Q_ARG (quint16, port));
I am getting an assert failure with this (Cannot send events to objects owned by a different thread.) Since I am fairly new to Qt I don't know if what I am doing is the correct thing.
Can somebody tell me if what I am doing is a good approach and if so why is my program crashing?
The best thing is never to call methods like waitForBlah() ... forcing the event loop to wait for an undetermined period introduces the possibility of the GUI freezing up during that time. Instead, connect your QTcpSocket's connected() signal to some slot that will update your GUI as appropriate, and let the event loop continue as usual. Do your on-connected stuff inside that slot.
I don't recommend start thread in constructor.
Initialize it like:
Client * client = new Client();
client->moveToThread(client);
client->start();
Or if you don't want to use such solution, add in constructor before start(); line this->moveToThread(this);
upd: sorry, i didn't saw at first time, that you have this string.

Resources