mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
parent
30b00741b5
commit
3abef972a7
@ -14,30 +14,30 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var clone = require("clone");
|
const clone = require("clone");
|
||||||
var log = require("@node-red/util").log;
|
const log = require("@node-red/util").log;
|
||||||
var util = require("@node-red/util").util;
|
const util = require("@node-red/util").util;
|
||||||
var memory = require("./memory");
|
const memory = require("./memory");
|
||||||
|
|
||||||
var settings;
|
let settings;
|
||||||
|
|
||||||
// A map of scope id to context instance
|
// A map of scope id to context instance
|
||||||
var contexts = {};
|
let contexts = {};
|
||||||
|
|
||||||
// A map of store name to instance
|
// A map of store name to instance
|
||||||
var stores = {};
|
let stores = {};
|
||||||
var storeList = [];
|
let storeList = [];
|
||||||
var defaultStore;
|
let defaultStore;
|
||||||
|
|
||||||
// Whether there context storage has been configured or left as default
|
// Whether there context storage has been configured or left as default
|
||||||
var hasConfiguredStore = false;
|
let hasConfiguredStore = false;
|
||||||
|
|
||||||
// Unknown Stores
|
// Unknown Stores
|
||||||
var unknownStores = {};
|
let unknownStores = {};
|
||||||
|
|
||||||
function logUnknownStore(name) {
|
function logUnknownStore(name) {
|
||||||
if (name) {
|
if (name) {
|
||||||
var count = unknownStores[name] || 0;
|
let count = unknownStores[name] || 0;
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
log.warn(log._("context.unknown-store", {name: name}));
|
log.warn(log._("context.unknown-store", {name: name}));
|
||||||
count++;
|
count++;
|
||||||
@ -52,8 +52,8 @@ function init(_settings) {
|
|||||||
stores = {};
|
stores = {};
|
||||||
storeList = [];
|
storeList = [];
|
||||||
hasConfiguredStore = false;
|
hasConfiguredStore = false;
|
||||||
var seed = settings.functionGlobalContext || {};
|
initialiseGlobalContext();
|
||||||
contexts['global'] = createContext("global",seed);
|
|
||||||
// create a default memory store - used by the unit tests that skip the full
|
// create a default memory store - used by the unit tests that skip the full
|
||||||
// `load()` initialisation sequence.
|
// `load()` initialisation sequence.
|
||||||
// If the user has any stores configured, this will be disgarded
|
// If the user has any stores configured, this will be disgarded
|
||||||
@ -61,6 +61,11 @@ function init(_settings) {
|
|||||||
defaultStore = "memory";
|
defaultStore = "memory";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initialiseGlobalContext() {
|
||||||
|
const seed = settings.functionGlobalContext || {};
|
||||||
|
contexts['global'] = createContext("global",seed);
|
||||||
|
}
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
return new Promise(function(resolve,reject) {
|
return new Promise(function(resolve,reject) {
|
||||||
// load & init plugins in settings.contextStorage
|
// load & init plugins in settings.contextStorage
|
||||||
@ -233,12 +238,15 @@ function validateContextKey(key) {
|
|||||||
|
|
||||||
function createContext(id,seed,parent) {
|
function createContext(id,seed,parent) {
|
||||||
// Seed is only set for global context - sourced from functionGlobalContext
|
// Seed is only set for global context - sourced from functionGlobalContext
|
||||||
var scope = id;
|
const scope = id;
|
||||||
var obj = seed || {};
|
const obj = {};
|
||||||
var seedKeys;
|
let seedKeys;
|
||||||
var insertSeedValues;
|
let insertSeedValues;
|
||||||
if (seed) {
|
if (seed) {
|
||||||
seedKeys = Object.keys(seed);
|
seedKeys = Object.keys(seed);
|
||||||
|
seedKeys.forEach(key => {
|
||||||
|
obj[key] = seed[key];
|
||||||
|
})
|
||||||
insertSeedValues = function(keys,values) {
|
insertSeedValues = function(keys,values) {
|
||||||
if (!Array.isArray(keys)) {
|
if (!Array.isArray(keys)) {
|
||||||
if (values[0] === undefined) {
|
if (values[0] === undefined) {
|
||||||
@ -540,8 +548,28 @@ function getContext(nodeId, flowId) {
|
|||||||
return newContext;
|
return newContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the context of the given node/flow/global
|
||||||
|
*
|
||||||
|
* If the user has configured a context store, this
|
||||||
|
* will no-op a request to delete node/flow context.
|
||||||
|
*/
|
||||||
function deleteContext(id,flowId) {
|
function deleteContext(id,flowId) {
|
||||||
if(!hasConfiguredStore){
|
if (id === "global") {
|
||||||
|
// 1. delete global from all configured stores
|
||||||
|
var promises = [];
|
||||||
|
for(var plugin in stores){
|
||||||
|
if(stores.hasOwnProperty(plugin)){
|
||||||
|
promises.push(stores[plugin].delete('global'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.all(promises).then(function() {
|
||||||
|
// 2. delete global context
|
||||||
|
delete contexts['global'];
|
||||||
|
// 3. reinitialise global context
|
||||||
|
initialiseGlobalContext();
|
||||||
|
})
|
||||||
|
} else if (!hasConfiguredStore) {
|
||||||
// only delete context if there's no configured storage.
|
// only delete context if there's no configured storage.
|
||||||
var contextId = id;
|
var contextId = id;
|
||||||
if (flowId) {
|
if (flowId) {
|
||||||
@ -549,12 +577,19 @@ function deleteContext(id,flowId) {
|
|||||||
}
|
}
|
||||||
delete contexts[contextId];
|
delete contexts[contextId];
|
||||||
return stores["_"].delete(contextId);
|
return stores["_"].delete(contextId);
|
||||||
}else{
|
} else {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete any contexts that are no longer in use
|
||||||
|
* @param flowConfig object includes allNodes as object of id->node
|
||||||
|
*
|
||||||
|
* If flowConfig is undefined, all flow/node contexts will be removed
|
||||||
|
**/
|
||||||
function clean(flowConfig) {
|
function clean(flowConfig) {
|
||||||
|
flowConfig = flowConfig || { allNodes: {} };
|
||||||
var promises = [];
|
var promises = [];
|
||||||
for(var plugin in stores){
|
for(var plugin in stores){
|
||||||
if(stores.hasOwnProperty(plugin)){
|
if(stores.hasOwnProperty(plugin)){
|
||||||
@ -572,6 +607,16 @@ function clean(flowConfig) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all contexts, including global and reinitialises global to
|
||||||
|
* initial state.
|
||||||
|
*/
|
||||||
|
function clear() {
|
||||||
|
return clean().then(function() {
|
||||||
|
return deleteContext('global')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
var promises = [];
|
var promises = [];
|
||||||
for(var plugin in stores){
|
for(var plugin in stores){
|
||||||
@ -594,5 +639,6 @@ module.exports = {
|
|||||||
getFlowContext:getFlowContext,
|
getFlowContext:getFlowContext,
|
||||||
delete: deleteContext,
|
delete: deleteContext,
|
||||||
clean: clean,
|
clean: clean,
|
||||||
|
clear: clear,
|
||||||
close: close
|
close: close
|
||||||
};
|
};
|
||||||
|
@ -206,6 +206,7 @@ module.exports = {
|
|||||||
eachNode: flows.eachNode,
|
eachNode: flows.eachNode,
|
||||||
getContext: context.get,
|
getContext: context.get,
|
||||||
|
|
||||||
|
clearContext: context.clear,
|
||||||
|
|
||||||
installerEnabled: registry.installerEnabled,
|
installerEnabled: registry.installerEnabled,
|
||||||
installModule: installModule,
|
installModule: installModule,
|
||||||
|
@ -378,15 +378,23 @@ function getActiveProject(user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reloadActiveProject(action) {
|
function reloadActiveProject(action) {
|
||||||
|
// Stop the current flows
|
||||||
return runtime.nodes.stopFlows().then(function() {
|
return runtime.nodes.stopFlows().then(function() {
|
||||||
return runtime.nodes.loadFlows(true).then(function() {
|
// Reset context to remove any old values
|
||||||
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
|
return runtime.nodes.clearContext().then(function() {
|
||||||
}).catch(function(err) {
|
// Load the new project flows and start them
|
||||||
// We're committed to the project change now, so notify editors
|
return runtime.nodes.loadFlows(true).then(function() {
|
||||||
// that it has changed.
|
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
|
||||||
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
|
}).catch(function(err) {
|
||||||
throw err;
|
// We're committed to the project change now, so notify editors
|
||||||
});
|
// that it has changed.
|
||||||
|
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}).catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
throw err;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function createProject(user, metadata) {
|
function createProject(user, metadata) {
|
||||||
|
@ -156,6 +156,22 @@ describe('context', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('deletes global context',function() {
|
||||||
|
Context.init({functionGlobalContext: {foo:"bar"}});
|
||||||
|
return Context.load().then(function(){
|
||||||
|
var globalContextA = Context.get("global")
|
||||||
|
|
||||||
|
globalContextA.get('foo').should.eql('bar')
|
||||||
|
globalContextA.set("another","value");
|
||||||
|
|
||||||
|
return Context.delete("global").then(function(){
|
||||||
|
var globalContextB = Context.get("global")
|
||||||
|
globalContextB.get('foo').should.eql('bar')
|
||||||
|
should.not.exist(globalContextB.get("another"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('enumerates context keys - sync', function() {
|
it('enumerates context keys - sync', function() {
|
||||||
var flowContextA = Context.getFlowContext("flowA")
|
var flowContextA = Context.getFlowContext("flowA")
|
||||||
var context = Context.get("1","flowA");
|
var context = Context.get("1","flowA");
|
||||||
@ -316,6 +332,31 @@ describe('context', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe("clear", function() {
|
||||||
|
it('clears all context',function() {
|
||||||
|
Context.init({functionGlobalContext: {foo:"bar"}});
|
||||||
|
return Context.load().then(function(){
|
||||||
|
var globalContextA = Context.get("global")
|
||||||
|
globalContextA.get('foo').should.eql('bar')
|
||||||
|
globalContextA.set("another","value");
|
||||||
|
|
||||||
|
var flowContextA = Context.getFlowContext("flowA")
|
||||||
|
flowContextA.set("foo","abc");
|
||||||
|
flowContextA.get("foo").should.equal("abc");
|
||||||
|
|
||||||
|
return Context.clear().then(function(){
|
||||||
|
var globalContextB = Context.getFlowContext("global")
|
||||||
|
globalContextB.get('foo').should.eql('bar')
|
||||||
|
should.not.exist(globalContextB.get("another"));
|
||||||
|
|
||||||
|
flowContextA = Context.getFlowContext("flowA")
|
||||||
|
should.not.exist(flowContextA.get("foo"))
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('external context storage',function() {
|
describe('external context storage',function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user