NodeJs/WS: How to throw an error server side handled on client side? - node.js

I'm trying to throw and error server side when my websocket has more than 2 connections. I have this nice client-side onerror method but I'm unable to reach that part of my code. I'm using nodeJS and the package ws which has the smallest doc on error handling.
server.js
theWebSocketServer.on('connection', function connection(websocket){
if (theWebSocketServer.clients.length >2) {
// I want to throw the error here and pass it to onerror
console.log('No access allowed', theWebSocketServer.clients.length)
} else {
console.log('happy connection', theWebSocketServer.clients.length)
}
})
client.js
wsConnection.onerror = function(eventInfo) {
alert("There was a connection error!");
console.log("Socket error!", eventInfo);
}
How can I send an error to be handled on the client side JS?

In the docs, I can't find any way to send an error to the client. Since ws is a smallish module for websockets, I think it can be used to send messages between server and client and if you need fancy stuff you need to implement your own protocol (the way how you interpret those messages).
For example, in this case it could be something like this:
Client
wsConnection.onmessage = (m) => {
// You can define errors by checking if the event data contains
// something specific: such as the message starts with "Error"
// or if the property of the object is "error" and so on.
if (m.data.startsWith("Error")) {
alert(m.data)
// This will show in the popup:
// "Error: No access allowed"
} else {
// do something else
}
};
wsConnection.onerror = function(eventInfo) {
/* Handle socket errors – e.g. internet goes down, connection is broken etc. */
}
Server:
theWebSocketServer.on('connection', function connection(websocket){
if (theWebSocketServer.clients.length >2) {
websocket.send("Error: No access allowed", err => {
// Ensure your data was actually sent successfully and then
// Close the connection
websocket.close()
// Just in case your data was not sent because
// of an error, you may be interested so see what happened
if (err) { return console.error(err); }
})
// I want to throw the error here and pass it to onerror
console.log('No access allowed', theWebSocketServer.clients.length)
} else {
console.log('happy connection', theWebSocketServer.clients.length)
}
})

Related

Nodejs response and console

I am creating a NodeJS API using Express, PostgreSQL in which I created a controller function which will check the user from the database.
const checkUser = async (req, res) => {
try {
const user = await pool.query('select * from users where email = $1', [req.body.email]);
if (user.rows.length === 0) throw new Error('Error Found');
return res.json("User Found");
} catch (e) {
//======= Output at console ========
//Error: Error Found
console.log(e);
//======== Response Object Received From API ==========
// {
// "msg": "Error Found",
// "Error": {}
// }
res.status(400).send({ msg: 'Error Found', Error: e });
}
};
Consider the situation that the user is not found in the Database so from try block the control passes to the catch block.
1- I am not able to get why the Error thrown from the try block to catch block sends back an empty object as a response. Also, at the same time using console.log prints the correct output value in the console.
2- I want a fix so that I can send e as a response to the User.
The problem is that Error objects are not that easy to serialize (which is intentional). This...
try {
throw new Error('Catch me if you can');
} catch(e) {
console.log(JSON.stringify(e)); // {}
}
... just logs {}, the same as for empty object, because Error objects don't have enumerable properties. And in your case, you don't send that object directly - but make it a property of another object sent to client.
However, there are several ways out of this. If you always need your client to get all the details of an Error, cast that to string (as toString() is overridden):
try {
throw new Error('Catch me if you can');
} catch(e) {
console.log(JSON.stringify(e.toString())); // "Error: Catch me if you can"
}
... or use Error object properties - name and message - as separate fields of your response:
res.status(400).send({
name: e.name || 'Anonymous Error',
msg: e.message || 'no message provided'
});
As sub-approach, you might consider choosing your status code based on type of error you have (always sending 404 for 'not founds', for example).

How to handle node.js errors properly - the standart way

For about developer errors that are made by mistake or undefined or something else that can crash the whole app:
Should I use this:
var domain = require('domain');
var d = domain.create();
d.on('error', function(err) {
console.error(err);
});
d.run(function() {
if (someom.sadjaslkd.asdasd=="yes") console.log("Yes");
// run more other things in the safe area
});
Purposely someom.sadjaslkd.asdasd is undefined.
OR should I use this:
try {
if (someom.sadjaslkd.asdasd=="yes") console.log("Yes");
// run more other things in the safe area
} catch(err) {
// handle the error safely
}
For about operation errors that are made not by mistake but due to client's faults:
Should I use this:
if (somethingWorng) res.status(400).json({status: "400", error: "Some custom error message to the user"});
OR maybe I should pass the error like this:
if (somethingWorng) throw "Some custom error message to the user";
OR maybe
if (somethingWorng) throw new Error("Some custom error message to the user");
Really there tons of ways to make this work. Is there a quick easy, readable, best practice?

Multiple connections with node cluster and socket.io

im using socket.io with sticky session (https://github.com/indutny/sticky-session). I have a little chat application and always when im using 2 or more sockets on one one machine the socket.on(...) event listener is firing very very slow. When i'm using only one socket-connection for each cluster everything works fine and fast. What could be the cause. Could it be because of sticky session?
Edit:
This is the socket- connect function (of my worker - clusters):
WebSockets.on('connect', function (socket) {
console.log(`${process.pid}`);
//send data example: socket.emit('news', {a: "b"});
//TODO: implement switch case that validates which chat type it is.
//TODO: why is the event so slow when using 2 connections?: https://socketio.slack.com/messages/C02AS4S1H/
socket.on('chat message', function (msg) {
console.log("sending message: " + msg)
try {
//send the message to all other cluster-workers:
process.send({ chat_message: msg });
} catch (e) { }
});
//if the cluster gets a message then he sends it to the user, if its the correct user
function message_handler(msg) {
try {
//TODO: send message only to the correct users
if (msg != null && msg.chat_message != null) {
WebSockets.emit('chat message', msg.chat_message);
}
} catch (e) { }
}
process.on('message', message_handler);
//When the socket disconnects:
socket.on('disconnect', function(reason) {
//remove the event listener:
process.removeListener('message', message_handler);
});
});
Explanation: I'm sending all the data i get from the socket to all the other clusters. Then I catch them with:
process.on('message', message_handler);
To send incomming chat messages.
I created the Clusters with sticky session like in the example (https://github.com/indutny/sticky-session)

Node returning before callback?

Sorry if this is due to a misunderstanding of how callbacks work, but I'm new to Node and really need to return useful error messages, but at the moment return a success followed later by the error which is caught:
connectDevice: function (ip) {
var port = 5555;
console.log("Connecting to device " + ip + ":5555")
client.connect(ip, port)
.then(function() {
return false; // wait until no errors confirmed
})
.catch(function(err) {
if (err === null) {
return false;
} else {
if (debug) console.error('Could not connect to device at IP ' + ip, err.stack);
console.log('Could not connect to device');
return true; // return error = true
}
});
},
I'm trying to connect to an android device using adbkit which uses promises, however I can't figure out how to adapt them from examples as there's no parent function.
It's important it waits to confirm a connecion before sending commands however. I get this is because of Node's event driven nature but don't know enough how to properly deal with this situation.
Thanks for any help and patience.

Using domain with serialport-node

I have the node-serialport library working fine in a happy-path situation, but I'd like to address error handling.
The particular test case I'm addressing at the moment is simply that the serial device isn't plugged in. Ideally, I'd be able to detect that a problem exists, and then just retry after a short delay.
The problem is that I keep getting the following error:
events.js:72
throw er; // Unhandled 'error' event
Error: cannot open /dev/ttyACM0
I would expect something like this, since the device isn't plugged in, but I need to catch it. try/catch obviously doesn't work, since it's asynchronous. So I am trying "domain", which appears to be the recommended way:
function reconnect() {
var d = domain.create();
d.on("error", function(err) {
console.error(err);
setTimeout(reconnect, RETRY_DELAY_MS);
});
d.run(function() {
var gps = new SerialPort("/dev/ttyACM0");
gps.on("open", function() {
console.log("Success!");
});
gps.on("error", function(err) {
console.error(err);
setTimeout(reconnect, RETRY_DELAY_MS);
});
});
}
I would expect this to have the desired effect, but I get the same error as above.
Does anyone see anything that I'm just not getting?
The trick is to provide a callback when instantiating the SerialPort object
var serial = new serialPort("/dev/ttyUSB0", { baudrate : 115200 },
function(error) {
if(error)
{
console.log("INIT ERROR: " + error.message + "\n");
}
});

Resources