mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Update Node/Flow to trigger msg routing hooks
This commit is contained in:
@@ -19,8 +19,7 @@ var redUtil = require("@node-red/util").util;
|
||||
var flowUtil = require("./util");
|
||||
var events = require("../events");
|
||||
const context = require('../nodes/context');
|
||||
const router = require("./router");
|
||||
|
||||
const hooks = require("../hooks");
|
||||
|
||||
var Subflow;
|
||||
var Log;
|
||||
@@ -545,8 +544,25 @@ class Flow {
|
||||
return asyncMessageDelivery
|
||||
}
|
||||
|
||||
send(src,destinationId,msg) {
|
||||
router.send(src,destinationId,msg);
|
||||
send(sendEvents) {
|
||||
// onSend - passed an array of SendEvent objects. The messages inside these objects are exactly what the node has passed to node.send - meaning there could be duplicate references to the same message object.
|
||||
// preRoute - called once for each SendEvent object in turn
|
||||
// preDeliver - the local router has identified the node it is going to send to. At this point, the message has been cloned if needed.
|
||||
// postDeliver - the message has been dispatched to be delivered asynchronously (unless the sync delivery flag is set, in which case it would be continue as synchronous delivery)
|
||||
// onReceive - a node is about to receive a message
|
||||
// postReceive - the message has been passed to the node's input handler
|
||||
// onDone, onError - the node has completed with a message or logged an error
|
||||
handleOnSend(this,sendEvents, (err, eventData) => {
|
||||
if (err) {
|
||||
let srcNode;
|
||||
if (Array.isArray(eventData)) {
|
||||
srcNode = eventData[0].source.node;
|
||||
} else {
|
||||
srcNode = eventData.source.node;
|
||||
}
|
||||
srcNode.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dump() {
|
||||
@@ -595,6 +611,61 @@ function stopNode(node,removed) {
|
||||
}
|
||||
|
||||
|
||||
function handleOnSend(flow,sendEvents, reportError) {
|
||||
// onSend - passed an array of SendEvent objects. The messages inside these objects are exactly what the node has passed to node.send - meaning there could be duplicate references to the same message object.
|
||||
hooks.trigger("onSend",sendEvents,(err) => {
|
||||
if (err) {
|
||||
reportError(err,sendEvents);
|
||||
return
|
||||
} else if (err !== false) {
|
||||
for (var i=0;i<sendEvents.length;i++) {
|
||||
handlePreRoute(flow,sendEvents[i],reportError)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handlePreRoute(flow, sendEvent, reportError) {
|
||||
// preRoute - called once for each SendEvent object in turn
|
||||
hooks.trigger("preRoute",sendEvent,(err) => {
|
||||
if (err) {
|
||||
reportError(err,sendEvent);
|
||||
return;
|
||||
} else if (err !== false) {
|
||||
sendEvent.destination.node = flow.getNode(sendEvent.destination.id);
|
||||
if (sendEvent.destination.node) {
|
||||
if (sendEvent.cloneMessage) {
|
||||
sendEvent.msg = redUtil.cloneMessage(sendEvent.msg);
|
||||
}
|
||||
handlePreDeliver(flow,sendEvent,reportError);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handlePreDeliver(flow,sendEvent, reportError) {
|
||||
// preDeliver - the local router has identified the node it is going to send to. At this point, the message has been cloned if needed.
|
||||
hooks.trigger("preDeliver",sendEvent,(err) => {
|
||||
if (err) {
|
||||
reportError(err,sendEvent);
|
||||
return;
|
||||
} else if (err !== false) {
|
||||
setImmediate(function() {
|
||||
if (sendEvent.destination.node) {
|
||||
sendEvent.destination.node.receive(sendEvent.msg);
|
||||
|
||||
}
|
||||
})
|
||||
// postDeliver - the message has been dispatched to be delivered asynchronously (unless the sync delivery flag is set, in which case it would be continue as synchronous delivery)
|
||||
hooks.trigger("postDeliver", sendEvent, function(err) {
|
||||
if (err) {
|
||||
reportError(err,sendEvent);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
nodeCloseTimeout = runtime.settings.nodeCloseTimeout || 15000;
|
||||
|
@@ -21,6 +21,8 @@ var redUtil = require("@node-red/util").util;
|
||||
var Log = require("@node-red/util").log;
|
||||
var context = require("./context");
|
||||
var flows = require("../flows");
|
||||
const hooks = require("../hooks");
|
||||
|
||||
|
||||
const NOOP_SEND = function() {}
|
||||
|
||||
@@ -121,6 +123,11 @@ Node.prototype.context = function() {
|
||||
*/
|
||||
Node.prototype._complete = function(msg,error) {
|
||||
this.metric("done",msg);
|
||||
hooks.trigger("onComplete",{ msg: msg, error: error, node: { id: this.id, node: this }}, err => {
|
||||
if (err) {
|
||||
this.error(err);
|
||||
}
|
||||
})
|
||||
if (error) {
|
||||
// For now, delegate this to this.error
|
||||
// But at some point, the timeout handling will need to know about
|
||||
@@ -183,42 +190,53 @@ Node.prototype.emit = function(event, ...args) {
|
||||
Node.prototype._emitInput = function(arg) {
|
||||
var node = this;
|
||||
this.metric("receive", arg);
|
||||
if (node._inputCallback) {
|
||||
// Just one callback registered.
|
||||
try {
|
||||
node._inputCallback(
|
||||
arg,
|
||||
function() { node.send.apply(node,arguments) },
|
||||
function(err) { node._complete(arg,err); }
|
||||
);
|
||||
} catch(err) {
|
||||
node.error(err,arg);
|
||||
}
|
||||
} else if (node._inputCallbacks) {
|
||||
// Multiple callbacks registered. Call each one, tracking eventual completion
|
||||
var c = node._inputCallbacks.length;
|
||||
for (var i=0;i<c;i++) {
|
||||
var cb = node._inputCallbacks[i];
|
||||
if (cb.length === 2) {
|
||||
c++;
|
||||
}
|
||||
try {
|
||||
cb.call(
|
||||
node,
|
||||
arg,
|
||||
function() { node.send.apply(node,arguments) },
|
||||
function(err) {
|
||||
c--;
|
||||
if (c === 0) {
|
||||
node._complete(arg,err);
|
||||
}
|
||||
let receiveEvent = { msg:arg, destination: { id: this.id, node: this } }
|
||||
// onReceive - a node is about to receive a message
|
||||
hooks.trigger("onReceive",receiveEvent,(err) => {
|
||||
if (err) {
|
||||
node.error(err);
|
||||
return
|
||||
} else if (err !== false) {
|
||||
if (node._inputCallback) {
|
||||
// Just one callback registered.
|
||||
try {
|
||||
node._inputCallback(
|
||||
arg,
|
||||
function() { node.send.apply(node,arguments) },
|
||||
function(err) { node._complete(arg,err); }
|
||||
);
|
||||
} catch(err) {
|
||||
node.error(err,arg);
|
||||
}
|
||||
} else if (node._inputCallbacks) {
|
||||
// Multiple callbacks registered. Call each one, tracking eventual completion
|
||||
var c = node._inputCallbacks.length;
|
||||
for (var i=0;i<c;i++) {
|
||||
var cb = node._inputCallbacks[i];
|
||||
if (cb.length === 2) {
|
||||
c++;
|
||||
}
|
||||
);
|
||||
} catch(err) {
|
||||
node.error(err,arg);
|
||||
try {
|
||||
cb.call(
|
||||
node,
|
||||
arg,
|
||||
function() { node.send.apply(node,arguments) },
|
||||
function(err) {
|
||||
c--;
|
||||
if (c === 0) {
|
||||
node._complete(arg,err);
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch(err) {
|
||||
node.error(err,arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
// postReceive - the message has been passed to the node's input handler
|
||||
hooks.trigger("postReceive",receiveEvent,(err) => {if (err) { node.error(err) }});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,7 +372,19 @@ Node.prototype.send = function(msg) {
|
||||
msg._msgid = redUtil.generateId();
|
||||
}
|
||||
this.metric("send",msg);
|
||||
this._flow.send(this,this._wire,msg);
|
||||
this._flow.send([{
|
||||
msg: msg,
|
||||
source: {
|
||||
id: this.id,
|
||||
node: this,
|
||||
port: 0
|
||||
},
|
||||
destination: {
|
||||
id: this._wire,
|
||||
node: undefined
|
||||
},
|
||||
cloneMessage: false
|
||||
}]);
|
||||
return;
|
||||
} else {
|
||||
msg = [msg];
|
||||
@@ -368,7 +398,7 @@ Node.prototype.send = function(msg) {
|
||||
var sendEvents = [];
|
||||
|
||||
var sentMessageId = null;
|
||||
|
||||
var hasMissingIds = false;
|
||||
// for each output of node eg. [msgs to output 0, msgs to output 1, ...]
|
||||
for (var i = 0; i < numOutputs; i++) {
|
||||
var wires = this.wires[i]; // wires leaving output i
|
||||
@@ -386,17 +416,27 @@ Node.prototype.send = function(msg) {
|
||||
for (k = 0; k < msgs.length; k++) {
|
||||
var m = msgs[k];
|
||||
if (m !== null && m !== undefined) {
|
||||
if (!m._msgid) {
|
||||
hasMissingIds = true;
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (!sentMessageId) {
|
||||
sentMessageId = m._msgid;
|
||||
}
|
||||
if (msgSent) {
|
||||
var clonedmsg = redUtil.cloneMessage(m);
|
||||
sendEvents.push({n:wires[j],m:clonedmsg});
|
||||
} else {
|
||||
sendEvents.push({n:wires[j],m:m});
|
||||
msgSent = true;
|
||||
}
|
||||
sendEvents.push({
|
||||
msg: m,
|
||||
source: {
|
||||
id: this.id,
|
||||
node: this,
|
||||
port: i
|
||||
},
|
||||
destination: {
|
||||
id: wires[j],
|
||||
node: undefined
|
||||
},
|
||||
cloneMessage: msgSent
|
||||
});
|
||||
msgSent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,21 +449,22 @@ Node.prototype.send = function(msg) {
|
||||
}
|
||||
this.metric("send",{_msgid:sentMessageId});
|
||||
|
||||
for (i=0;i<sendEvents.length;i++) {
|
||||
var ev = sendEvents[i];
|
||||
/* istanbul ignore else */
|
||||
if (!ev.m._msgid) {
|
||||
ev.m._msgid = sentMessageId;
|
||||
if (hasMissingIds) {
|
||||
for (i=0;i<sendEvents.length;i++) {
|
||||
var ev = sendEvents[i];
|
||||
/* istanbul ignore else */
|
||||
if (!ev.msg._msgid) {
|
||||
ev.msg._msgid = sentMessageId;
|
||||
}
|
||||
}
|
||||
this._flow.send(this,ev.n,ev.m);
|
||||
}
|
||||
this._flow.send(sendEvents);
|
||||
};
|
||||
|
||||
/**
|
||||
* Receive a message.
|
||||
*
|
||||
* This will emit the `input` event with the provided message.
|
||||
* As of 1.0, this will return *before* any 'input' callback handler is invoked.
|
||||
*/
|
||||
Node.prototype.receive = function(msg) {
|
||||
if (!msg) {
|
||||
|
Reference in New Issue
Block a user