node-red-contrib-self-healing
Version:
SHEN: Self-healing extensions for Node-RED.
112 lines (103 loc) • 3.41 kB
JavaScript
module.exports = function (RED) {
function Debounce(config) {
RED.nodes.createNode(this, config);
let node = this;
let delayInMilis = parseInt(config.delay) * 1000;
let delayInterval =
config.delayInterval != null ? parseInt(config.delayInterval) : 0;
let schedule = "undefined";
let allActions = []; //all msg payloads
let lastMsgTimestamp = null;
function resetSchedule() {
clearInterval(schedule);
schedule = "undefined";
}
const executeMsg = (send, done) => {
if (allActions.length == 0) {
// no messages to be sent
resetSchedule();
} else if (config.strategy == "allByOrder") {
// send all messages by order
send([allActions.shift(), null]);
done();
} else if (config.strategy == "last") {
// send the last message received
send([allActions.pop(), null]);
allActions = []; // clear message payload
resetSchedule();
done();
} else if (config.strategy == "first") {
//send the first message received
send([allActions.shift(), null]);
allActions = [];
resetSchedule();
done();
}
};
node.on("input", function (msg, send, done) {
const newMsgTimestamp = new Date().getTime();
//input message contains a cancel order
//clear current state and schedulers
if (Object.prototype.hasOwnProperty.call(msg, "cancel")) {
resetSchedule();
allActions = [];
this.lastMsgTimestamp = null;
delete msg.cancel;
}
// first message
if (this.lastMsgTimestamp == null) {
node.status({
fill: "green",
shape: "dot",
text: "First",
});
if (Object.prototype.hasOwnProperty.call(msg, "payload")) {
//only consider msg if it has a payload
this.lastMsgTimestamp = newMsgTimestamp; // add latest sent message timestamp
node.send([msg, null]);
}
done();
return;
}
// message is within interval
// and there is no message backlog
// pass message, all clear and good
if (
newMsgTimestamp - lastMsgTimestamp >= delayInMilis - delayInterval &&
allActions.length == 0
) {
node.status({ fill: "green", shape: "dot", text: "Dispatched" });
lastMsgTimestamp = newMsgTimestamp; // update latest sent message timestamp
send([msg, null]);
done();
return;
}
// message isn't within interval
if (newMsgTimestamp - lastMsgTimestamp < delayInMilis - delayInterval) {
allActions.push(msg); // add message to payload
node.status({
fill: "yellow",
shape: "dot",
text: "Delayed: " + allActions.length,
});
const newMsg = msg;
newMsg.timestamp = newMsgTimestamp;
send([null, msg]);
done();
}
if (config.strategy == "discard") {
allActions = []; // clear payload
} else if (schedule == "undefined") {
schedule = setInterval(executeMsg, delayInMilis, send, done);
}
});
node.on("close", function () {
resetSchedule();
schedule = "undefined";
allActions = []; //all msg payloads
lastMsgTimestamp = null;
node.status({});
});
}
RED.nodes.registerType("debounce", Debounce);
};