UNPKG

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