@node-red/runtime 2.2.0-beta.1 → 2.2.0
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/LICENSE +1 -1
- package/lib/api/projects.js +2 -1
- package/lib/flows/Flow.js +18 -1
- package/lib/flows/Subflow.js +11 -0
- package/lib/flows/util.js +1 -0
- package/lib/nodes/Node.js +3 -0
- package/lib/nodes/context/index.js +66 -20
- package/lib/nodes/index.js +1 -0
- package/lib/storage/localfilesystem/projects/index.js +15 -3
- package/package.json +3 -3
package/LICENSE
CHANGED
package/lib/api/projects.js
CHANGED
|
@@ -99,6 +99,7 @@ var api = module.exports = {
|
|
|
99
99
|
* @param {Object} opts
|
|
100
100
|
* @param {User} opts.user - the user calling the api
|
|
101
101
|
* @param {String} opts.id - the id of the project to activate
|
|
102
|
+
* @param {boolean} opts.clearContext - whether to clear context
|
|
102
103
|
* @param {Object} opts.req - the request to log (optional)
|
|
103
104
|
* @return {Promise<Object>} - resolves when complete
|
|
104
105
|
* @memberof @node-red/runtime_projects
|
|
@@ -107,7 +108,7 @@ var api = module.exports = {
|
|
|
107
108
|
var currentProject = runtime.storage.projects.getActiveProject(opts.user);
|
|
108
109
|
runtime.log.audit({event: "projects.set",id:opts.id}, opts.req);
|
|
109
110
|
if (!currentProject || opts.id !== currentProject.name) {
|
|
110
|
-
return runtime.storage.projects.setActiveProject(opts.user, opts.id);
|
|
111
|
+
return runtime.storage.projects.setActiveProject(opts.user, opts.id, opts.clearContext);
|
|
111
112
|
}
|
|
112
113
|
},
|
|
113
114
|
|
package/lib/flows/Flow.js
CHANGED
|
@@ -424,6 +424,17 @@ class Flow {
|
|
|
424
424
|
*/
|
|
425
425
|
getGroupEnvSetting(node, group, name) {
|
|
426
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
|
+
|
|
427
438
|
if (group.credentials === undefined) {
|
|
428
439
|
group.credentials = credentials.get(group.id) || {};
|
|
429
440
|
}
|
|
@@ -498,7 +509,13 @@ class Flow {
|
|
|
498
509
|
* @return {[type]} [description]
|
|
499
510
|
*/
|
|
500
511
|
getSetting(key) {
|
|
501
|
-
const flow = this.flow;
|
|
512
|
+
const flow = this.flow;
|
|
513
|
+
if (key === "NR_FLOW_NAME") {
|
|
514
|
+
return flow.label;
|
|
515
|
+
}
|
|
516
|
+
if (key === "NR_FLOW_ID") {
|
|
517
|
+
return flow.id;
|
|
518
|
+
}
|
|
502
519
|
if (flow.credentials === undefined) {
|
|
503
520
|
flow.credentials = credentials.get(flow.id) || {};
|
|
504
521
|
}
|
package/lib/flows/Subflow.js
CHANGED
|
@@ -371,6 +371,17 @@ class Subflow extends Flow {
|
|
|
371
371
|
name = name.substring(8);
|
|
372
372
|
}
|
|
373
373
|
const node = this.subflowInstance;
|
|
374
|
+
if (node) {
|
|
375
|
+
if (name === "NR_NODE_NAME") {
|
|
376
|
+
return node.name;
|
|
377
|
+
}
|
|
378
|
+
if (name === "NR_NODE_ID") {
|
|
379
|
+
return node.id;
|
|
380
|
+
}
|
|
381
|
+
if (name === "NR_NODE_PATH") {
|
|
382
|
+
return node._path;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
374
385
|
if (node.g) {
|
|
375
386
|
const group = this.getGroupNode(node.g);
|
|
376
387
|
const [result, newName] = this.getGroupEnvSetting(node, group, name);
|
package/lib/flows/util.js
CHANGED
|
@@ -85,6 +85,7 @@ function createNode(flow,config) {
|
|
|
85
85
|
try {
|
|
86
86
|
Object.defineProperty(conf,'_module', {value: typeRegistry.getNodeInfo(type), enumerable: false, writable: true })
|
|
87
87
|
Object.defineProperty(conf,'_flow', {value: flow, enumerable: false, writable: true })
|
|
88
|
+
Object.defineProperty(conf,'_path', {value: `${flow.path}/${config._alias||config.id}`, enumerable: false, writable: true })
|
|
88
89
|
newNode = new nodeTypeConstructor(conf);
|
|
89
90
|
} catch (err) {
|
|
90
91
|
Log.log({
|
package/lib/nodes/Node.js
CHANGED
|
@@ -62,6 +62,9 @@ function Node(n) {
|
|
|
62
62
|
if (n._module) {
|
|
63
63
|
Object.defineProperty(this,'_module', {value: n._module, enumerable: false, writable: true })
|
|
64
64
|
}
|
|
65
|
+
if (n._path) {
|
|
66
|
+
Object.defineProperty(this,'_path', {value: n._path, enumerable: false, writable: true })
|
|
67
|
+
}
|
|
65
68
|
this.updateWires(n.wires);
|
|
66
69
|
}
|
|
67
70
|
|
|
@@ -14,30 +14,30 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
**/
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const clone = require("clone");
|
|
18
|
+
const log = require("@node-red/util").log;
|
|
19
|
+
const util = require("@node-red/util").util;
|
|
20
|
+
const memory = require("./memory");
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
let settings;
|
|
23
23
|
|
|
24
24
|
// A map of scope id to context instance
|
|
25
|
-
|
|
25
|
+
let contexts = {};
|
|
26
26
|
|
|
27
27
|
// A map of store name to instance
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
let stores = {};
|
|
29
|
+
let storeList = [];
|
|
30
|
+
let defaultStore;
|
|
31
31
|
|
|
32
32
|
// Whether there context storage has been configured or left as default
|
|
33
|
-
|
|
33
|
+
let hasConfiguredStore = false;
|
|
34
34
|
|
|
35
35
|
// Unknown Stores
|
|
36
|
-
|
|
36
|
+
let unknownStores = {};
|
|
37
37
|
|
|
38
38
|
function logUnknownStore(name) {
|
|
39
39
|
if (name) {
|
|
40
|
-
|
|
40
|
+
let count = unknownStores[name] || 0;
|
|
41
41
|
if (count == 0) {
|
|
42
42
|
log.warn(log._("context.unknown-store", {name: name}));
|
|
43
43
|
count++;
|
|
@@ -52,8 +52,8 @@ function init(_settings) {
|
|
|
52
52
|
stores = {};
|
|
53
53
|
storeList = [];
|
|
54
54
|
hasConfiguredStore = false;
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
initialiseGlobalContext();
|
|
56
|
+
|
|
57
57
|
// create a default memory store - used by the unit tests that skip the full
|
|
58
58
|
// `load()` initialisation sequence.
|
|
59
59
|
// If the user has any stores configured, this will be disgarded
|
|
@@ -61,6 +61,11 @@ function init(_settings) {
|
|
|
61
61
|
defaultStore = "memory";
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
function initialiseGlobalContext() {
|
|
65
|
+
const seed = settings.functionGlobalContext || {};
|
|
66
|
+
contexts['global'] = createContext("global",seed);
|
|
67
|
+
}
|
|
68
|
+
|
|
64
69
|
function load() {
|
|
65
70
|
return new Promise(function(resolve,reject) {
|
|
66
71
|
// load & init plugins in settings.contextStorage
|
|
@@ -233,12 +238,15 @@ function validateContextKey(key) {
|
|
|
233
238
|
|
|
234
239
|
function createContext(id,seed,parent) {
|
|
235
240
|
// Seed is only set for global context - sourced from functionGlobalContext
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
const scope = id;
|
|
242
|
+
const obj = {};
|
|
243
|
+
let seedKeys;
|
|
244
|
+
let insertSeedValues;
|
|
240
245
|
if (seed) {
|
|
241
246
|
seedKeys = Object.keys(seed);
|
|
247
|
+
seedKeys.forEach(key => {
|
|
248
|
+
obj[key] = seed[key];
|
|
249
|
+
})
|
|
242
250
|
insertSeedValues = function(keys,values) {
|
|
243
251
|
if (!Array.isArray(keys)) {
|
|
244
252
|
if (values[0] === undefined) {
|
|
@@ -540,8 +548,28 @@ function getContext(nodeId, flowId) {
|
|
|
540
548
|
return newContext;
|
|
541
549
|
}
|
|
542
550
|
|
|
551
|
+
/**
|
|
552
|
+
* Delete the context of the given node/flow/global
|
|
553
|
+
*
|
|
554
|
+
* If the user has configured a context store, this
|
|
555
|
+
* will no-op a request to delete node/flow context.
|
|
556
|
+
*/
|
|
543
557
|
function deleteContext(id,flowId) {
|
|
544
|
-
if(
|
|
558
|
+
if (id === "global") {
|
|
559
|
+
// 1. delete global from all configured stores
|
|
560
|
+
var promises = [];
|
|
561
|
+
for(var plugin in stores){
|
|
562
|
+
if(stores.hasOwnProperty(plugin)){
|
|
563
|
+
promises.push(stores[plugin].delete('global'));
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return Promise.all(promises).then(function() {
|
|
567
|
+
// 2. delete global context
|
|
568
|
+
delete contexts['global'];
|
|
569
|
+
// 3. reinitialise global context
|
|
570
|
+
initialiseGlobalContext();
|
|
571
|
+
})
|
|
572
|
+
} else if (!hasConfiguredStore) {
|
|
545
573
|
// only delete context if there's no configured storage.
|
|
546
574
|
var contextId = id;
|
|
547
575
|
if (flowId) {
|
|
@@ -549,12 +577,19 @@ function deleteContext(id,flowId) {
|
|
|
549
577
|
}
|
|
550
578
|
delete contexts[contextId];
|
|
551
579
|
return stores["_"].delete(contextId);
|
|
552
|
-
}else{
|
|
580
|
+
} else {
|
|
553
581
|
return Promise.resolve();
|
|
554
582
|
}
|
|
555
583
|
}
|
|
556
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Delete any contexts that are no longer in use
|
|
587
|
+
* @param flowConfig object includes allNodes as object of id->node
|
|
588
|
+
*
|
|
589
|
+
* If flowConfig is undefined, all flow/node contexts will be removed
|
|
590
|
+
**/
|
|
557
591
|
function clean(flowConfig) {
|
|
592
|
+
flowConfig = flowConfig || { allNodes: {} };
|
|
558
593
|
var promises = [];
|
|
559
594
|
for(var plugin in stores){
|
|
560
595
|
if(stores.hasOwnProperty(plugin)){
|
|
@@ -572,6 +607,16 @@ function clean(flowConfig) {
|
|
|
572
607
|
return Promise.all(promises);
|
|
573
608
|
}
|
|
574
609
|
|
|
610
|
+
/**
|
|
611
|
+
* Deletes all contexts, including global and reinitialises global to
|
|
612
|
+
* initial state.
|
|
613
|
+
*/
|
|
614
|
+
function clear() {
|
|
615
|
+
return clean().then(function() {
|
|
616
|
+
return deleteContext('global')
|
|
617
|
+
})
|
|
618
|
+
}
|
|
619
|
+
|
|
575
620
|
function close() {
|
|
576
621
|
var promises = [];
|
|
577
622
|
for(var plugin in stores){
|
|
@@ -594,5 +639,6 @@ module.exports = {
|
|
|
594
639
|
getFlowContext:getFlowContext,
|
|
595
640
|
delete: deleteContext,
|
|
596
641
|
clean: clean,
|
|
642
|
+
clear: clear,
|
|
597
643
|
close: close
|
|
598
644
|
};
|
package/lib/nodes/index.js
CHANGED
|
@@ -377,8 +377,17 @@ function getActiveProject(user) {
|
|
|
377
377
|
return activeProject;
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
function reloadActiveProject(action) {
|
|
380
|
+
function reloadActiveProject(action, clearContext) {
|
|
381
|
+
// Stop the current flows
|
|
381
382
|
return runtime.nodes.stopFlows().then(function() {
|
|
383
|
+
if (clearContext) {
|
|
384
|
+
// Reset context to remove any old values
|
|
385
|
+
return runtime.nodes.clearContext()
|
|
386
|
+
} else {
|
|
387
|
+
return Promise.resolve()
|
|
388
|
+
}
|
|
389
|
+
}).then(function() {
|
|
390
|
+
// Load the new project flows and start them
|
|
382
391
|
return runtime.nodes.loadFlows(true).then(function() {
|
|
383
392
|
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
|
|
384
393
|
}).catch(function(err) {
|
|
@@ -387,6 +396,9 @@ function reloadActiveProject(action) {
|
|
|
387
396
|
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
|
|
388
397
|
throw err;
|
|
389
398
|
});
|
|
399
|
+
}).catch(function(err) {
|
|
400
|
+
console.log(err.stack);
|
|
401
|
+
throw err;
|
|
390
402
|
});
|
|
391
403
|
}
|
|
392
404
|
function createProject(user, metadata) {
|
|
@@ -424,7 +436,7 @@ function createProject(user, metadata) {
|
|
|
424
436
|
return getProject(user, metadata.name);
|
|
425
437
|
})
|
|
426
438
|
}
|
|
427
|
-
function setActiveProject(user, projectName) {
|
|
439
|
+
function setActiveProject(user, projectName, clearContext) {
|
|
428
440
|
return loadProject(projectName).then(function(project) {
|
|
429
441
|
var globalProjectSettings = settings.get("projects")||{};
|
|
430
442
|
globalProjectSettings.activeProject = project.name;
|
|
@@ -434,7 +446,7 @@ function setActiveProject(user, projectName) {
|
|
|
434
446
|
// console.log("Updated file targets to");
|
|
435
447
|
// console.log(flowsFullPath)
|
|
436
448
|
// console.log(credentialsFile)
|
|
437
|
-
return reloadActiveProject("loaded");
|
|
449
|
+
return reloadActiveProject("loaded", clearContext);
|
|
438
450
|
})
|
|
439
451
|
});
|
|
440
452
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-red/runtime",
|
|
3
|
-
"version": "2.2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@node-red/registry": "2.2.0
|
|
20
|
-
"@node-red/util": "2.2.0
|
|
19
|
+
"@node-red/registry": "2.2.0",
|
|
20
|
+
"@node-red/util": "2.2.0",
|
|
21
21
|
"async-mutex": "0.3.2",
|
|
22
22
|
"clone": "2.1.2",
|
|
23
23
|
"express": "4.17.2",
|