node-red-contrib-error-on-timeout
Version:
Node that triggers an error if a message is not received within the configured time frame. Also has an output for "late" messages.
140 lines (122 loc) • 4.5 kB
JavaScript
const nodeState = {
// Node is waiting for the trigger message
Idle: Symbol("idle"),
// Node is waiting for the input message
Active: Symbol("active"),
// Node is
Timeout: Symbol("timeout"),
};
module.exports = function (RED) {
function ErrorOnTimeout(config) {
// Create the node
RED.nodes.createNode(this, config);
// Node variable
var node = this;
// Current state
let state = nodeState.Idle;
let verbose = config.verbose;
// Get the timeout from the ui
let timeout = parseInt(config.timeout);
// Copy of the trigger message
let triggerMessage = null;
// The date and time of reception of the trigger message
let triggerMessageReceivedAt = null;
// Input event wiring
node.on("input", function (msg) {
// We're idle, so let's make sure that all requirements are met
if (state === nodeState.Idle) {
// Check for absent trigger message
if (!msg.eot_trigger) {
if(verbose) {
node.error("Need to receive a trigger message first");
}
node.status({
fill: "red",
shape: "dot",
text: "Need to receive a trigger message first",
});
return [null, null, null];
} else {
// When we received the trigger message
triggerMessageReceivedAt = Date.now();
// Save a copy of the trigger message
triggerMessage = msg;
// Check if the trigger message is contains a programmatically added interval
if (msg.eot_timeout) {
// Set the timeout to the interval
timeout = parseInt(msg.eot_timeout);
}
// Start the interval timer
setTimeout(() => {
if (state === nodeState.Active) {
const errorMessage = `Input message not received within ${timeout} ms`;
// We timed out, so let's send an error message
state = nodeState.Timeout;
node.status({
fill: "red",
shape: "dot",
text: errorMessage,
});
node.send([
null,
{ topic: "error-on-timeout", payload: errorMessage, eot_timeout: timeout, eot_trigger: triggerMessage },
null,
]);
}
}, timeout);
// We're active, so let's start the timer
state = nodeState.Active;
node.status({
fill: "green",
shape: "dot",
text: "Trigger message received, waiting for input",
});
}
} else if (state === nodeState.Active) {
// Here's the input message
if (msg.eot_input) {
// Switch to idle state
state = nodeState.Idle;
// Calulcate the time difference
const timeDifference = Date.now() - triggerMessageReceivedAt;
// Set the status
node.status({
fill: "green",
shape: "dot",
text: `Message received within ${timeDifference} ms`,
});
// Sanitize the message before sending it out
delete msg.eot_input;
node.send([{...msg, eot_time: timeDifference, eot_timeout: timeout}, null, null]);
} else {
const errorMessage = "Received message without eot_input property";
// We received a message that does not match our required parameters
if(verbose) {
node.error(errorMessage);
}
node.status({
fill: "grey",
shape: "dot",
text: errorMessage,
});
node.send([null, null, null]);
}
} else if (state === nodeState.Timeout) {
if (msg.eot_input) {
const lateBy = Date.now() - triggerMessageReceivedAt - timeout;
const errorMessage = `Message arrived ${lateBy} ms late`;
node.status({
fill: "grey",
shape: "dot",
text: errorMessage,
});
state = nodeState.Idle;
// Sanitize the msg
delete msg.eot_input;
node.send([null, null, {...msg, eot_late: lateBy, eot_timeout: timeout, eot_time: lateBy+ timeout}]);
}
}
});
}
RED.nodes.registerType("error-on-timeout", ErrorOnTimeout);
};