@node-red/runtime 3.1.0-beta.3 → 3.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/flows/Flow.js +81 -156
- package/lib/flows/Group.js +55 -0
- package/lib/flows/Subflow.js +19 -52
- package/lib/flows/index.js +14 -20
- package/lib/flows/util.js +478 -416
- package/lib/nodes/index.js +0 -1
- package/package.json +3 -3
package/lib/flows/Flow.js
CHANGED
|
@@ -14,19 +14,20 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const clone = require("clone");
|
|
18
|
+
const redUtil = require("@node-red/util").util;
|
|
19
19
|
const events = require("@node-red/util").events;
|
|
20
|
-
|
|
20
|
+
const flowUtil = require("./util");
|
|
21
21
|
const context = require('../nodes/context');
|
|
22
22
|
const hooks = require("@node-red/util").hooks;
|
|
23
23
|
const credentials = require("../nodes/credentials");
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
let Subflow;
|
|
26
|
+
let Log;
|
|
27
|
+
let Group;
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
let nodeCloseTimeout = 15000;
|
|
30
|
+
let asyncMessageDelivery = true;
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* This class represents a flow within the runtime. It is responsible for
|
|
@@ -52,6 +53,8 @@ class Flow {
|
|
|
52
53
|
this.isGlobalFlow = false;
|
|
53
54
|
}
|
|
54
55
|
this.id = this.flow.id || "global";
|
|
56
|
+
this.groups = {}
|
|
57
|
+
this.groupOrder = []
|
|
55
58
|
this.activeNodes = {};
|
|
56
59
|
this.subflowInstanceNodes = {};
|
|
57
60
|
this.catchNodes = [];
|
|
@@ -59,6 +62,11 @@ class Flow {
|
|
|
59
62
|
this.path = this.id;
|
|
60
63
|
// Ensure a context exists for this flow
|
|
61
64
|
this.context = context.getFlowContext(this.id,this.parent.id);
|
|
65
|
+
|
|
66
|
+
// env is an array of env definitions
|
|
67
|
+
// _env is an object for direct lookup of env name -> value
|
|
68
|
+
this.env = this.flow.env
|
|
69
|
+
this._env = {}
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
/**
|
|
@@ -136,7 +144,7 @@ class Flow {
|
|
|
136
144
|
* @param {[type]} msg [description]
|
|
137
145
|
* @return {[type]} [description]
|
|
138
146
|
*/
|
|
139
|
-
start(diff) {
|
|
147
|
+
async start(diff) {
|
|
140
148
|
this.trace("start "+this.TYPE+" ["+this.path+"]");
|
|
141
149
|
var node;
|
|
142
150
|
var newNode;
|
|
@@ -145,6 +153,52 @@ class Flow {
|
|
|
145
153
|
this.statusNodes = [];
|
|
146
154
|
this.completeNodeMap = {};
|
|
147
155
|
|
|
156
|
+
|
|
157
|
+
if (this.isGlobalFlow) {
|
|
158
|
+
// This is the global flow. It needs to go find the `global-config`
|
|
159
|
+
// node and extract any env properties from it
|
|
160
|
+
const configNodes = Object.keys(this.flow.configs);
|
|
161
|
+
for (let i = 0; i < configNodes.length; i++) {
|
|
162
|
+
const node = this.flow.configs[configNodes[i]]
|
|
163
|
+
if (node.type === 'global-config' && node.env) {
|
|
164
|
+
const nodeEnv = await flowUtil.evaluateEnvProperties(this, node.env, credentials.get(node.id))
|
|
165
|
+
this._env = { ...this._env, ...nodeEnv }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (this.env) {
|
|
171
|
+
this._env = { ...this._env, ...await flowUtil.evaluateEnvProperties(this, this.env, credentials.get(this.id)) }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Initialise the group objects. These must be done in the right order
|
|
175
|
+
// starting from outer-most to inner-most so that the parent hierarchy
|
|
176
|
+
// is maintained.
|
|
177
|
+
this.groups = {}
|
|
178
|
+
this.groupOrder = []
|
|
179
|
+
const groupIds = Object.keys(this.flow.groups || {})
|
|
180
|
+
while (groupIds.length > 0) {
|
|
181
|
+
const id = groupIds.shift()
|
|
182
|
+
const groupDef = this.flow.groups[id]
|
|
183
|
+
if (!groupDef.g || this.groups[groupDef.g]) {
|
|
184
|
+
// The parent of this group is available - either another group
|
|
185
|
+
// or the top-level flow (this)
|
|
186
|
+
const parent = this.groups[groupDef.g] || this
|
|
187
|
+
this.groups[groupDef.id] = new Group(parent, groupDef)
|
|
188
|
+
this.groupOrder.push(groupDef.id)
|
|
189
|
+
} else {
|
|
190
|
+
// Try again once we've processed the other groups
|
|
191
|
+
groupIds.push(id)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < this.groupOrder.length; i++) {
|
|
196
|
+
// Start the groups in the right order so they
|
|
197
|
+
// can setup their env vars knowning their parent
|
|
198
|
+
// will have been started
|
|
199
|
+
await this.groups[this.groupOrder[i]].start()
|
|
200
|
+
}
|
|
201
|
+
|
|
148
202
|
var configNodes = Object.keys(this.flow.configs);
|
|
149
203
|
var configNodeAttempts = {};
|
|
150
204
|
while (configNodes.length > 0) {
|
|
@@ -177,7 +231,7 @@ class Flow {
|
|
|
177
231
|
}
|
|
178
232
|
}
|
|
179
233
|
if (readyToCreate) {
|
|
180
|
-
newNode = flowUtil.createNode(this,node);
|
|
234
|
+
newNode = await flowUtil.createNode(this,node);
|
|
181
235
|
if (newNode) {
|
|
182
236
|
this.activeNodes[id] = newNode;
|
|
183
237
|
}
|
|
@@ -203,7 +257,7 @@ class Flow {
|
|
|
203
257
|
if (node.d !== true) {
|
|
204
258
|
if (!node.subflow) {
|
|
205
259
|
if (!this.activeNodes[id]) {
|
|
206
|
-
newNode = flowUtil.createNode(this,node);
|
|
260
|
+
newNode = await flowUtil.createNode(this,node);
|
|
207
261
|
if (newNode) {
|
|
208
262
|
this.activeNodes[id] = newNode;
|
|
209
263
|
}
|
|
@@ -221,7 +275,7 @@ class Flow {
|
|
|
221
275
|
node
|
|
222
276
|
);
|
|
223
277
|
this.subflowInstanceNodes[id] = subflow;
|
|
224
|
-
subflow.start();
|
|
278
|
+
await subflow.start();
|
|
225
279
|
this.activeNodes[id] = subflow.node;
|
|
226
280
|
|
|
227
281
|
// this.subflowInstanceNodes[id] = nodes.map(function(n) { return n.id});
|
|
@@ -404,8 +458,7 @@ class Flow {
|
|
|
404
458
|
* @return {Node} group node
|
|
405
459
|
*/
|
|
406
460
|
getGroupNode(id) {
|
|
407
|
-
|
|
408
|
-
return groups[id];
|
|
461
|
+
return this.groups[id];
|
|
409
462
|
}
|
|
410
463
|
|
|
411
464
|
/**
|
|
@@ -416,95 +469,8 @@ class Flow {
|
|
|
416
469
|
return this.activeNodes;
|
|
417
470
|
}
|
|
418
471
|
|
|
419
|
-
/*!
|
|
420
|
-
* Get value of environment variable defined in group node.
|
|
421
|
-
* @param {String} group - group node
|
|
422
|
-
* @param {String} name - name of variable
|
|
423
|
-
* @return {Object} object containing the value in val property or null if not defined
|
|
424
|
-
*/
|
|
425
|
-
getGroupEnvSetting(node, group, name) {
|
|
426
|
-
if (group) {
|
|
427
|
-
if (name === "NR_GROUP_NAME") {
|
|
428
|
-
return [{
|
|
429
|
-
val: group.name
|
|
430
|
-
}, null];
|
|
431
|
-
}
|
|
432
|
-
if (name === "NR_GROUP_ID") {
|
|
433
|
-
return [{
|
|
434
|
-
val: group.id
|
|
435
|
-
}, null];
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
if (group.credentials === undefined) {
|
|
439
|
-
group.credentials = credentials.get(group.id) || {};
|
|
440
|
-
}
|
|
441
|
-
if (!name.startsWith("$parent.")) {
|
|
442
|
-
if (group.env) {
|
|
443
|
-
if (!group._env) {
|
|
444
|
-
const envs = group.env;
|
|
445
|
-
const entries = envs.map((env) => {
|
|
446
|
-
if (env.type === "cred") {
|
|
447
|
-
const cred = group.credentials;
|
|
448
|
-
if (cred.hasOwnProperty(env.name)) {
|
|
449
|
-
env.value = cred[env.name];
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
return [env.name, env];
|
|
453
|
-
});
|
|
454
|
-
group._env = Object.fromEntries(entries);
|
|
455
|
-
}
|
|
456
|
-
const env = group._env[name];
|
|
457
|
-
if (env) {
|
|
458
|
-
let value = env.value;
|
|
459
|
-
const type = env.type;
|
|
460
|
-
if ((type !== "env") ||
|
|
461
|
-
(value !== name)) {
|
|
462
|
-
if (type === "env") {
|
|
463
|
-
value = value.replace(new RegExp("\\${"+name+"}","g"),"${$parent."+name+"}");
|
|
464
|
-
}
|
|
465
|
-
if (type === "bool") {
|
|
466
|
-
const val
|
|
467
|
-
= ((value === "true") ||
|
|
468
|
-
(value === true));
|
|
469
|
-
return [{
|
|
470
|
-
val: val
|
|
471
|
-
}, null];
|
|
472
|
-
}
|
|
473
|
-
if (type === "cred") {
|
|
474
|
-
return [{
|
|
475
|
-
val: value
|
|
476
|
-
}, null];
|
|
477
|
-
}
|
|
478
|
-
try {
|
|
479
|
-
var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
|
|
480
|
-
return [{
|
|
481
|
-
val: val
|
|
482
|
-
}, null];
|
|
483
|
-
}
|
|
484
|
-
catch (e) {
|
|
485
|
-
this.error(e);
|
|
486
|
-
return [null, null];
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
else {
|
|
493
|
-
name = name.substring(8);
|
|
494
|
-
}
|
|
495
|
-
if (group.g) {
|
|
496
|
-
const parent = this.getGroupNode(group.g);
|
|
497
|
-
return this.getGroupEnvSetting(node, parent, name);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return [null, name];
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
|
|
504
472
|
/**
|
|
505
|
-
* Get a flow setting value.
|
|
506
|
-
* flow which, as defined in ./index.js returns `process.env[key]`.
|
|
507
|
-
* This lays the groundwork for Subflow to have instance-specific settings
|
|
473
|
+
* Get a flow setting value.
|
|
508
474
|
* @param {[type]} key [description]
|
|
509
475
|
* @return {[type]} [description]
|
|
510
476
|
*/
|
|
@@ -516,54 +482,14 @@ class Flow {
|
|
|
516
482
|
if (key === "NR_FLOW_ID") {
|
|
517
483
|
return flow.id;
|
|
518
484
|
}
|
|
519
|
-
if (
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
if (flow.env) {
|
|
523
|
-
if (!key.startsWith("$parent.")) {
|
|
524
|
-
if (!flow._env) {
|
|
525
|
-
const envs = flow.env;
|
|
526
|
-
const entries = envs.map((env) => {
|
|
527
|
-
if (env.type === "cred") {
|
|
528
|
-
const cred = flow.credentials;
|
|
529
|
-
if (cred.hasOwnProperty(env.name)) {
|
|
530
|
-
env.value = cred[env.name];
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return [env.name, env]
|
|
534
|
-
});
|
|
535
|
-
flow._env = Object.fromEntries(entries);
|
|
536
|
-
}
|
|
537
|
-
const env = flow._env[key];
|
|
538
|
-
if (env) {
|
|
539
|
-
let value = env.value;
|
|
540
|
-
const type = env.type;
|
|
541
|
-
if ((type !== "env") || (value !== key)) {
|
|
542
|
-
if (type === "env") {
|
|
543
|
-
value = value.replace(new RegExp("\\${"+key+"}","g"),"${$parent."+key+"}");
|
|
544
|
-
}
|
|
545
|
-
try {
|
|
546
|
-
if (type === "bool") {
|
|
547
|
-
const val = ((value === "true") ||
|
|
548
|
-
(value === true));
|
|
549
|
-
return val;
|
|
550
|
-
}
|
|
551
|
-
if (type === "cred") {
|
|
552
|
-
return value;
|
|
553
|
-
}
|
|
554
|
-
var val = redUtil.evaluateNodeProperty(value, type, null, null, null);
|
|
555
|
-
return val;
|
|
556
|
-
}
|
|
557
|
-
catch (e) {
|
|
558
|
-
this.error(e);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
485
|
+
if (!key.startsWith("$parent.")) {
|
|
486
|
+
if (this._env.hasOwnProperty(key)) {
|
|
487
|
+
return this._env[key]
|
|
562
488
|
}
|
|
563
|
-
|
|
489
|
+
} else {
|
|
564
490
|
key = key.substring(8);
|
|
565
|
-
}
|
|
566
491
|
}
|
|
492
|
+
// Delegate to the parent flow.
|
|
567
493
|
return this.parent.getSetting(key);
|
|
568
494
|
}
|
|
569
495
|
|
|
@@ -601,10 +527,9 @@ class Flow {
|
|
|
601
527
|
// Delegate status to any nodes using this config node
|
|
602
528
|
for (let userNode in node.users) {
|
|
603
529
|
if (node.users.hasOwnProperty(userNode)) {
|
|
604
|
-
node.users[userNode]._flow.handleStatus(node,statusMessage,node.users[userNode],true);
|
|
530
|
+
handled = node.users[userNode]._flow.handleStatus(node,statusMessage,node.users[userNode],true) || handled;
|
|
605
531
|
}
|
|
606
532
|
}
|
|
607
|
-
handled = true;
|
|
608
533
|
} else {
|
|
609
534
|
const candidateNodes = [];
|
|
610
535
|
this.statusNodes.forEach(targetStatusNode => {
|
|
@@ -618,10 +543,10 @@ class Flow {
|
|
|
618
543
|
let distance = 0
|
|
619
544
|
if (reportingNode.g) {
|
|
620
545
|
// Reporting node inside a group. Calculate the distance between it and the status node
|
|
621
|
-
let containingGroup = this.
|
|
546
|
+
let containingGroup = this.groups[reportingNode.g]
|
|
622
547
|
while (containingGroup && containingGroup.id !== targetStatusNode.g) {
|
|
623
548
|
distance++
|
|
624
|
-
containingGroup = this.
|
|
549
|
+
containingGroup = this.groups[containingGroup.g]
|
|
625
550
|
}
|
|
626
551
|
if (!containingGroup && targetStatusNode.g && targetStatusNode.scope === 'group') {
|
|
627
552
|
// This status node is in a group, but not in the same hierachy
|
|
@@ -688,10 +613,9 @@ class Flow {
|
|
|
688
613
|
// Delegate status to any nodes using this config node
|
|
689
614
|
for (let userNode in node.users) {
|
|
690
615
|
if (node.users.hasOwnProperty(userNode)) {
|
|
691
|
-
node.users[userNode]._flow.handleError(node,logMessage,msg,node.users[userNode]);
|
|
616
|
+
handled = node.users[userNode]._flow.handleError(node,logMessage,msg,node.users[userNode]) || handled;
|
|
692
617
|
}
|
|
693
618
|
}
|
|
694
|
-
handled = true;
|
|
695
619
|
} else {
|
|
696
620
|
const candidateNodes = [];
|
|
697
621
|
this.catchNodes.forEach(targetCatchNode => {
|
|
@@ -706,10 +630,10 @@ class Flow {
|
|
|
706
630
|
let distance = 0
|
|
707
631
|
if (reportingNode.g) {
|
|
708
632
|
// Reporting node inside a group. Calculate the distance between it and the catch node
|
|
709
|
-
let containingGroup = this.
|
|
633
|
+
let containingGroup = this.groups[reportingNode.g]
|
|
710
634
|
while (containingGroup && containingGroup.id !== targetCatchNode.g) {
|
|
711
635
|
distance++
|
|
712
|
-
containingGroup = this.
|
|
636
|
+
containingGroup = this.groups[containingGroup.g]
|
|
713
637
|
}
|
|
714
638
|
if (!containingGroup && targetCatchNode.g && targetCatchNode.scope === 'group') {
|
|
715
639
|
// This catch node is in a group, but not in the same hierachy
|
|
@@ -859,7 +783,7 @@ function handlePreRoute(flow, sendEvent, reportError) {
|
|
|
859
783
|
return;
|
|
860
784
|
} else if (err !== false) {
|
|
861
785
|
sendEvent.destination.node = flow.getNode(sendEvent.destination.id);
|
|
862
|
-
if (sendEvent.destination.node) {
|
|
786
|
+
if (sendEvent.destination.node && typeof sendEvent.destination.node === 'object') {
|
|
863
787
|
if (sendEvent.cloneMessage) {
|
|
864
788
|
sendEvent.msg = redUtil.cloneMessage(sendEvent.msg);
|
|
865
789
|
}
|
|
@@ -909,9 +833,10 @@ module.exports = {
|
|
|
909
833
|
asyncMessageDelivery = !runtime.settings.runtimeSyncDelivery
|
|
910
834
|
Log = runtime.log;
|
|
911
835
|
Subflow = require("./Subflow");
|
|
836
|
+
Group = require("./Group").Group
|
|
912
837
|
},
|
|
913
838
|
create: function(parent,global,conf) {
|
|
914
|
-
return new Flow(parent,global,conf)
|
|
839
|
+
return new Flow(parent,global,conf)
|
|
915
840
|
},
|
|
916
841
|
Flow: Flow
|
|
917
842
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const flowUtil = require("./util");
|
|
2
|
+
const credentials = require("../nodes/credentials");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This class represents a group within the runtime.
|
|
6
|
+
*/
|
|
7
|
+
class Group {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create a Group object.
|
|
11
|
+
* @param {[type]} parent The parent flow/group
|
|
12
|
+
* @param {[type]} groupDef This group's definition
|
|
13
|
+
*/
|
|
14
|
+
constructor(parent, groupDef) {
|
|
15
|
+
this.TYPE = 'group'
|
|
16
|
+
this.name = groupDef.name
|
|
17
|
+
this.parent = parent
|
|
18
|
+
this.group = groupDef
|
|
19
|
+
this.id = this.group.id
|
|
20
|
+
this.g = this.group.g
|
|
21
|
+
this.env = this.group.env
|
|
22
|
+
this._env = {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async start() {
|
|
26
|
+
if (this.env) {
|
|
27
|
+
this._env = await flowUtil.evaluateEnvProperties(this, this.env, credentials.get(this.id))
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get a group setting value.
|
|
32
|
+
* @param {[type]} key [description]
|
|
33
|
+
* @return {[type]} [description]
|
|
34
|
+
*/
|
|
35
|
+
getSetting(key) {
|
|
36
|
+
if (key === "NR_GROUP_NAME") {
|
|
37
|
+
return this.name;
|
|
38
|
+
}
|
|
39
|
+
if (key === "NR_GROUP_ID") {
|
|
40
|
+
return this.id;
|
|
41
|
+
}
|
|
42
|
+
if (!key.startsWith("$parent.")) {
|
|
43
|
+
if (this._env.hasOwnProperty(key)) {
|
|
44
|
+
return this._env[key]
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
key = key.substring(8);
|
|
48
|
+
}
|
|
49
|
+
return this.parent.getSetting(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
Group
|
|
55
|
+
}
|
package/lib/flows/Subflow.js
CHANGED
|
@@ -119,7 +119,7 @@ class Subflow extends Flow {
|
|
|
119
119
|
this.templateCredentials = credentials.get(subflowDef.id) || {};
|
|
120
120
|
this.instanceCredentials = credentials.get(id) || {};
|
|
121
121
|
|
|
122
|
-
var env =
|
|
122
|
+
var env = {};
|
|
123
123
|
if (this.subflowDef.env) {
|
|
124
124
|
this.subflowDef.env.forEach(e => {
|
|
125
125
|
env[e.name] = e;
|
|
@@ -145,7 +145,7 @@ class Subflow extends Flow {
|
|
|
145
145
|
}
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
|
-
this.env = env;
|
|
148
|
+
this.env = Object.values(env);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
@@ -156,7 +156,7 @@ class Subflow extends Flow {
|
|
|
156
156
|
* @param {[type]} diff [description]
|
|
157
157
|
* @return {[type]} [description]
|
|
158
158
|
*/
|
|
159
|
-
start(diff) {
|
|
159
|
+
async start(diff) {
|
|
160
160
|
var self = this;
|
|
161
161
|
// Create a subflow node to accept inbound messages and route appropriately
|
|
162
162
|
var Node = require("../nodes/Node");
|
|
@@ -310,7 +310,7 @@ class Subflow extends Flow {
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
|
-
super.start(diff);
|
|
313
|
+
return super.start(diff);
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
/**
|
|
@@ -335,68 +335,35 @@ class Subflow extends Flow {
|
|
|
335
335
|
}
|
|
336
336
|
/**
|
|
337
337
|
* Get environment variable of subflow
|
|
338
|
-
* @param {String}
|
|
338
|
+
* @param {String} key name of env var
|
|
339
339
|
* @return {Object} val value of env var
|
|
340
340
|
*/
|
|
341
|
-
getSetting(
|
|
342
|
-
if (!/^\$parent\./.test(name)) {
|
|
343
|
-
var env = this.env;
|
|
344
|
-
if (env && env.hasOwnProperty(name)) {
|
|
345
|
-
var val = env[name];
|
|
346
|
-
// If this is an env type property we need to be careful not
|
|
347
|
-
// to get into lookup loops.
|
|
348
|
-
// 1. if the value to lookup is the same as this one, go straight to parent
|
|
349
|
-
// 2. otherwise, check if it is a compound env var ("foo $(bar)")
|
|
350
|
-
// and if so, substitute any instances of `name` with $parent.name
|
|
351
|
-
// See https://github.com/node-red/node-red/issues/2099
|
|
352
|
-
if (val.type !== 'env' || val.value !== name) {
|
|
353
|
-
let value = val.value;
|
|
354
|
-
var type = val.type;
|
|
355
|
-
if (type === 'env') {
|
|
356
|
-
value = value.replace(new RegExp("\\${"+name+"}","g"),"${$parent."+name+"}");
|
|
357
|
-
}
|
|
358
|
-
try {
|
|
359
|
-
return evaluateInputValue(value, type, this.node);
|
|
360
|
-
}
|
|
361
|
-
catch (e) {
|
|
362
|
-
this.error(e);
|
|
363
|
-
return undefined;
|
|
364
|
-
}
|
|
365
|
-
} else {
|
|
366
|
-
// This _is_ an env property pointing at itself - go to parent
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
} else {
|
|
370
|
-
// name starts $parent. ... so delegate to parent automatically
|
|
371
|
-
name = name.substring(8);
|
|
372
|
-
}
|
|
341
|
+
getSetting(key) {
|
|
373
342
|
const node = this.subflowInstance;
|
|
374
343
|
if (node) {
|
|
375
|
-
if (
|
|
344
|
+
if (key === "NR_NODE_NAME" || key === "NR_SUBFLOW_NAME") {
|
|
376
345
|
return node.name;
|
|
377
346
|
}
|
|
378
|
-
if (
|
|
347
|
+
if (key === "NR_NODE_ID" || key === "NR_SUBFLOW_ID") {
|
|
379
348
|
return node.id;
|
|
380
349
|
}
|
|
381
|
-
if (
|
|
350
|
+
if (key === "NR_NODE_PATH" || key === "NR_SUBFLOW_PATH") {
|
|
382
351
|
return node._path;
|
|
383
352
|
}
|
|
384
353
|
}
|
|
385
|
-
if (
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if (result) {
|
|
389
|
-
return result.val;
|
|
354
|
+
if (!key.startsWith("$parent.")) {
|
|
355
|
+
if (this._env.hasOwnProperty(key)) {
|
|
356
|
+
return this._env[key]
|
|
390
357
|
}
|
|
391
|
-
|
|
358
|
+
} else {
|
|
359
|
+
key = key.substring(8);
|
|
392
360
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (
|
|
396
|
-
|
|
397
|
-
return val;
|
|
361
|
+
// Push the request up to the parent.
|
|
362
|
+
// Unlike a Flow, the parent of a Subflow could be a Group
|
|
363
|
+
if (node.g) {
|
|
364
|
+
return this.parent.getGroupNode(node.g).getSetting(key)
|
|
398
365
|
}
|
|
399
|
-
return
|
|
366
|
+
return this.parent.getSetting(key)
|
|
400
367
|
}
|
|
401
368
|
|
|
402
369
|
/**
|
package/lib/flows/index.js
CHANGED
|
@@ -271,6 +271,10 @@ function getFlows() {
|
|
|
271
271
|
|
|
272
272
|
async function start(type,diff,muteLog,isDeploy) {
|
|
273
273
|
type = type || "full";
|
|
274
|
+
if (diff && diff.globalConfigChanged) {
|
|
275
|
+
type = 'full'
|
|
276
|
+
}
|
|
277
|
+
|
|
274
278
|
started = true;
|
|
275
279
|
state = 'start'
|
|
276
280
|
var i;
|
|
@@ -359,7 +363,7 @@ async function start(type,diff,muteLog,isDeploy) {
|
|
|
359
363
|
if (activeFlowConfig.flows.hasOwnProperty(id)) {
|
|
360
364
|
if (!activeFlowConfig.flows[id].disabled && !activeFlows[id]) {
|
|
361
365
|
// This flow is not disabled, nor is it currently active, so create it
|
|
362
|
-
activeFlows[id] = Flow.create(
|
|
366
|
+
activeFlows[id] = Flow.create(activeFlows['global'],activeFlowConfig,activeFlowConfig.flows[id]);
|
|
363
367
|
log.debug("red/nodes/flows.start : starting flow : "+id);
|
|
364
368
|
} else {
|
|
365
369
|
log.debug("red/nodes/flows.start : not starting disabled flow : "+id);
|
|
@@ -379,7 +383,7 @@ async function start(type,diff,muteLog,isDeploy) {
|
|
|
379
383
|
activeFlows[id].update(activeFlowConfig,activeFlowConfig.flows[id]);
|
|
380
384
|
} else {
|
|
381
385
|
// This flow didn't previously exist, so create it
|
|
382
|
-
activeFlows[id] = Flow.create(
|
|
386
|
+
activeFlows[id] = Flow.create(activeFlows['global'],activeFlowConfig,activeFlowConfig.flows[id]);
|
|
383
387
|
log.debug("red/nodes/flows.start : starting flow : "+id);
|
|
384
388
|
}
|
|
385
389
|
} else {
|
|
@@ -391,7 +395,7 @@ async function start(type,diff,muteLog,isDeploy) {
|
|
|
391
395
|
for (id in activeFlows) {
|
|
392
396
|
if (activeFlows.hasOwnProperty(id)) {
|
|
393
397
|
try {
|
|
394
|
-
activeFlows[id].start(diff);
|
|
398
|
+
await activeFlows[id].start(diff);
|
|
395
399
|
// Create a map of node id to flow id and also a subflowInstance lookup map
|
|
396
400
|
var activeNodes = activeFlows[id].getActiveNodes();
|
|
397
401
|
Object.keys(activeNodes).forEach(function(nid) {
|
|
@@ -432,7 +436,8 @@ function stop(type,diff,muteLog,isDeploy) {
|
|
|
432
436
|
changed:[],
|
|
433
437
|
removed:[],
|
|
434
438
|
rewired:[],
|
|
435
|
-
linked:[]
|
|
439
|
+
linked:[],
|
|
440
|
+
flowChanged:[]
|
|
436
441
|
};
|
|
437
442
|
if (!muteLog) {
|
|
438
443
|
if (type !== "full") {
|
|
@@ -441,6 +446,9 @@ function stop(type,diff,muteLog,isDeploy) {
|
|
|
441
446
|
log.info(log._("nodes.flows.stopping-flows"));
|
|
442
447
|
}
|
|
443
448
|
}
|
|
449
|
+
if (diff.globalConfigChanged) {
|
|
450
|
+
type = 'full'
|
|
451
|
+
}
|
|
444
452
|
started = false;
|
|
445
453
|
state = 'stop'
|
|
446
454
|
var promises = [];
|
|
@@ -464,7 +472,7 @@ function stop(type,diff,muteLog,isDeploy) {
|
|
|
464
472
|
|
|
465
473
|
activeFlowIds.forEach(id => {
|
|
466
474
|
if (activeFlows.hasOwnProperty(id)) {
|
|
467
|
-
var flowStateChanged = diff && (diff.added.indexOf(id) !== -1 || diff.removed.indexOf(id) !== -1);
|
|
475
|
+
var flowStateChanged = diff && (diff.flowChanged.indexOf(id) !== -1 || diff.added.indexOf(id) !== -1 || diff.removed.indexOf(id) !== -1);
|
|
468
476
|
log.debug("red/nodes/flows.stop : stopping flow : "+id);
|
|
469
477
|
promises.push(activeFlows[id].stop(flowStateChanged?null:stopList,removedList));
|
|
470
478
|
if (type === "full" || flowStateChanged || diff.removed.indexOf(id)!==-1) {
|
|
@@ -784,17 +792,6 @@ const flowAPI = {
|
|
|
784
792
|
log: m => log.log(m)
|
|
785
793
|
}
|
|
786
794
|
|
|
787
|
-
|
|
788
|
-
function getGlobalConfig() {
|
|
789
|
-
let gconf = null;
|
|
790
|
-
eachNode((n) => {
|
|
791
|
-
if (n.type === "global-config") {
|
|
792
|
-
gconf = n;
|
|
793
|
-
}
|
|
794
|
-
});
|
|
795
|
-
return gconf;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
795
|
module.exports = {
|
|
799
796
|
init: init,
|
|
800
797
|
|
|
@@ -807,10 +804,7 @@ module.exports = {
|
|
|
807
804
|
|
|
808
805
|
get:getNode,
|
|
809
806
|
eachNode: eachNode,
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
getGlobalConfig: getGlobalConfig,
|
|
813
|
-
|
|
807
|
+
|
|
814
808
|
/**
|
|
815
809
|
* Gets the current flow configuration
|
|
816
810
|
*/
|