1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add clean to context plugin

and don't delete local context unless the context is deleted by a user
This commit is contained in:
HirokiUchikawa 2018-05-30 15:23:34 +09:00
parent 7185bcd51f
commit f262348497
8 changed files with 260 additions and 107 deletions

View File

@ -105,12 +105,12 @@ Node.prototype.close = function(removed) {
if (promises.length > 0) { if (promises.length > 0) {
return when.settle(promises).then(function() { return when.settle(promises).then(function() {
if (this._context) { if (this._context) {
context.delete(this._alias||this.id,this.z); return context.delete(this._alias||this.id,this.z);
} }
}); });
} else { } else {
if (this._context) { if (this._context) {
context.delete(this._alias||this.id,this.z); return context.delete(this._alias||this.id,this.z);
} }
return; return;
} }

View File

@ -70,6 +70,11 @@ function load() {
return when.reject(new Error(log._("context.error-module-not-defined", {storage:pluginName}))); return when.reject(new Error(log._("context.error-module-not-defined", {storage:pluginName})));
} }
} }
for(var plugin in externalContexts){
if(externalContexts.hasOwnProperty(plugin)){
promises.push(externalContexts[plugin].open());
}
}
if(isAlias){ if(isAlias){
if(externalContexts.hasOwnProperty(plugins["default"])){ if(externalContexts.hasOwnProperty(plugins["default"])){
externalContexts["default"] = externalContexts[plugins["default"]]; externalContexts["default"] = externalContexts[plugins["default"]];
@ -77,11 +82,6 @@ function load() {
return when.reject(new Error(log._("context.error-invalid-default-module", {storage:plugins["default"]}))); return when.reject(new Error(log._("context.error-invalid-default-module", {storage:plugins["default"]})));
} }
} }
for(var plugin in externalContexts){
if(externalContexts.hasOwnProperty(plugin)){
promises.push(externalContexts[plugin].open());
}
}
return when.all(promises); return when.all(promises);
} else { } else {
noContextStorage = true; noContextStorage = true;
@ -191,31 +191,35 @@ function getContext(localId,flowId) {
} }
function deleteContext(id,flowId) { function deleteContext(id,flowId) {
var contextId = id; if(noContextStorage){
if (flowId) { var promises = [];
contextId = id+":"+flowId; var contextId = id;
if (flowId) {
contextId = id+":"+flowId;
}
delete contexts[contextId];
return externalContexts["_"].delete(contextId);
}else{
return when.resolve();
} }
for(var plugin in externalContexts){
externalContexts[plugin].delete(contextId);
}
delete contexts[contextId];
} }
function clean(flowConfig) { function clean(flowConfig) {
var activeIds = {}; var promises = [];
var contextId; for(var plugin in externalContexts){
var node; if(externalContexts.hasOwnProperty(plugin)){
promises.push(externalContexts[plugin].clean(Object.keys(flowConfig.allNodes)));
}
}
for (var id in contexts) { for (var id in contexts) {
if (contexts.hasOwnProperty(id)) { if (contexts.hasOwnProperty(id)) {
var idParts = id.split(":"); var idParts = id.split(":");
if (!flowConfig.allNodes.hasOwnProperty(idParts[0])) { if (!flowConfig.allNodes.hasOwnProperty(idParts[0])) {
for(var plugin in externalContexts){
externalContexts[plugin].delete(id);
}
delete contexts[id]; delete contexts[id];
} }
} }
} }
return when.all(promises);
} }
function close() { function close() {

View File

@ -78,7 +78,7 @@ LocalFileSystem.prototype.close = function(){
LocalFileSystem.prototype.get = function (scope, key) { LocalFileSystem.prototype.get = function (scope, key) {
if(!this.storages[scope]){ if(!this.storages[scope]){
return undefined; this.storages[scope] = createStorage(this.storageBaseDir ,scope);
} }
try{ try{
this.storages[scope].reload(); this.storages[scope].reload();
@ -105,28 +105,38 @@ LocalFileSystem.prototype.set = function(scope, key, value) {
LocalFileSystem.prototype.keys = function(scope) { LocalFileSystem.prototype.keys = function(scope) {
if(!this.storages[scope]){ if(!this.storages[scope]){
return []; this.storages[scope] = createStorage(this.storageBaseDir ,scope);
} }
return Object.keys(this.storages[scope].getData("/")); return Object.keys(this.storages[scope].getData("/"));
} }
LocalFileSystem.prototype.delete = function(scope){ LocalFileSystem.prototype.delete = function(scope){
var self = this;
if(this.storages[scope]){ if(this.storages[scope]){
var promise;
this.storages[scope].delete("/"); this.storages[scope].delete("/");
if(scope.indexOf(":") === -1){ return fs.remove(this.storages[scope].filename).then(function(){
fs.removeSync(path.dirname(this.storages[scope].filename)); delete self.storages[scope];
}else{ return when.resolve();
try{ });
fs.statSync(this.storages[scope].filename); }else{
fs.unlinkSync(this.storages[scope].filename); return when.resolve();
}catch(err){
console.log("deleted");
}
}
delete this.storages[scope];
} }
} }
LocalFileSystem.prototype.clean = function(activeNodes){
var self = this;
return fs.readdir(self.storageBaseDir).then(function(dirs){
return when.all(dirs.reduce(function(result, item){
if(item !== "global" && !activeNodes.includes(item)){
result.push(fs.remove(path.join(self.storageBaseDir,item)));
delete self.storages[item];
}
return result;
},[]));
});
}
module.exports = function(config){ module.exports = function(config){
return new LocalFileSystem(config); return new LocalFileSystem(config);
}; };

View File

@ -58,9 +58,21 @@ Memory.prototype.keys = function(scope){
Memory.prototype.delete = function(scope){ Memory.prototype.delete = function(scope){
delete this.data[scope]; delete this.data[scope];
return Promise.resolve();
}; };
Memory.prototype.clean = function(activeNodes){
for(var id in this.data){
if(this.data.hasOwnProperty(id) && id !== "global"){
var idParts = id.split(":");
if(!activeNodes.includes(idParts[0])){
delete this.data[id];
}
}
}
return Promise.resolve();
}
Memory.prototype.setGlobalContext= function(seed){ Memory.prototype.setGlobalContext= function(seed){
this.data["global"] = seed; this.data["global"] = seed;
}; };

View File

@ -160,11 +160,12 @@ function setFlows(_config,type,muteLog,forceStart) {
activeFlowConfig = newFlowConfig; activeFlowConfig = newFlowConfig;
if (forceStart || started) { if (forceStart || started) {
return stop(type,diff,muteLog).then(function() { return stop(type,diff,muteLog).then(function() {
context.clean(activeFlowConfig); return context.clean(activeFlowConfig).then(function() {
start(type,diff,muteLog).then(function() { start(type,diff,muteLog).then(function() {
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
});
return flowRevision;
}); });
return flowRevision;
}).catch(function(err) { }).catch(function(err) {
}) })
} else { } else {

View File

@ -118,9 +118,10 @@ describe('context', function() {
context.set("foo","abc"); context.set("foo","abc");
context.get("foo").should.eql("abc"); context.get("foo").should.eql("abc");
Context.delete("1","flowA"); return Context.delete("1","flowA").then(function(){
context = Context.get("1","flowA"); context = Context.get("1","flowA");
should.not.exist(context.get("foo")); should.not.exist(context.get("foo"));
});
}); });
it('enumerates context keys', function() { it('enumerates context keys', function() {
@ -153,12 +154,75 @@ describe('context', function() {
}); });
describe('external context storage',function() { describe('external context storage',function() {
describe('load modules',function(){ var sandbox = sinon.sandbox.create();
afterEach(function() { var stubGet = sandbox.stub();
Context.clean({allNodes:{}}); var stubSet = sandbox.stub();
var stubKeys = sandbox.stub();
var stubDelete = sandbox.stub().returns(Promise.resolve());
var stubClean = sandbox.stub().returns(Promise.resolve());
var stubOpen = sandbox.stub().returns(Promise.resolve());
var stubClose = sandbox.stub().returns(Promise.resolve());
var stubGet2 = sandbox.stub();
var stubSet2 = sandbox.stub();
var stubKeys2 = sandbox.stub();
var stubDelete2 = sandbox.stub().returns(Promise.resolve());
var stubClean2 = sandbox.stub().returns(Promise.resolve());
var stubOpen2 = sandbox.stub().returns(Promise.resolve());
var stubClose2 = sandbox.stub().returns(Promise.resolve());
var testPlugin = function(config){
function Test(){}
Test.prototype.get = stubGet;
Test.prototype.set = stubSet;
Test.prototype.keys = stubKeys;
Test.prototype.delete = stubDelete;
Test.prototype.clean = stubClean;
Test.prototype.open = stubOpen;
Test.prototype.close = stubClose;
return new Test(config);
};
var testPlugin2 = function(config){
function Test2(){}
Test2.prototype.get = stubGet2;
Test2.prototype.set = stubSet2;
Test2.prototype.keys = stubKeys2;
Test2.prototype.delete = stubDelete2;
Test2.prototype.clean = stubClean2;
Test2.prototype.open = stubOpen2;
Test2.prototype.close = stubClose2;
return new Test2(config);
};
var contextStorage={
test:{
module: testPlugin,
config:{}
}
};
var contextDefaultStorage={
default: {
module: testPlugin2,
config:{}
},
test:{
module: testPlugin,
config:{}
}
};
afterEach(function() {
sandbox.reset();
return Context.clean({allNodes:{}}).then(function(){
return Context.close(); return Context.close();
}); });
});
describe('load modules',function(){
it('should call open()', function() {
Context.init({contextStorage:contextDefaultStorage});
return Context.load().then(function(){
stubOpen.called.should.be.true();
stubOpen2.called.should.be.true();
});
});
it('should load memory module', function() { it('should load memory module', function() {
Context.init({contextStorage:{memory:{module:"memory"}}}); Context.init({contextStorage:{memory:{module:"memory"}}});
return Context.load(); return Context.load();
@ -185,6 +249,18 @@ describe('context', function() {
context.get("#1.num").should.eql("num3"); context.get("#1.num").should.eql("num3");
}); });
}); });
it('should ignore reserved storage name `_`', function() {
Context.init({contextStorage:{_:{module:testPlugin}}});
return Context.load().then(function(){
var context = Context.get("1","flow");
context.set("#_.foo","bar");
context.get("#_.foo");
context.keys("#_");
stubSet.called.should.be.false();
stubGet.called.should.be.false();
stubKeys.called.should.be.false();
});
});
it('should fail when using invalid default context', function(done) { it('should fail when using invalid default context', function(done) {
Context.init({contextStorage:{default:"noexist"}}); Context.init({contextStorage:{default:"noexist"}});
Context.load().then(function(){ Context.load().then(function(){
@ -211,63 +287,19 @@ describe('context', function() {
}); });
}); });
describe('store data',function() { describe('close modules',function(){
var sandbox = sinon.sandbox.create(); it('should call close()', function() {
var stubGet = sandbox.stub(); Context.init({contextStorage:contextDefaultStorage});
var stubSet = sandbox.stub(); return Context.load().then(function(){
var stubKeys = sandbox.stub(); return Context.close().then(function(){
var stubDelete = sandbox.stub(); stubClose.called.should.be.true();
var stubOpen = sandbox.stub().returns(Promise.resolve()); stubClose2.called.should.be.true();
var stubClose = sandbox.stub().returns(Promise.resolve()); });
var stubGet2 = sandbox.stub(); });
var stubSet2 = sandbox.stub();
var stubKeys2 = sandbox.stub();
var stubDelete2 = sandbox.stub();
var stubOpen2 = sandbox.stub().returns(Promise.resolve());
var stubClose2 = sandbox.stub().returns(Promise.resolve());
var testPlugin = function(config){
function Test(){}
Test.prototype.get = stubGet;
Test.prototype.set = stubSet;
Test.prototype.keys = stubKeys;
Test.prototype.delete = stubDelete;
Test.prototype.open = stubOpen;
Test.prototype.close = stubClose;
return new Test(config);
};
var testPlugin2 = function(config){
function Test2(){}
Test2.prototype.get = stubGet2;
Test2.prototype.set = stubSet2;
Test2.prototype.keys = stubKeys2;
Test2.prototype.delete = stubDelete2;
Test2.prototype.open = stubOpen2;
Test2.prototype.close = stubClose2;
return new Test2(config);
};
var contextStorage={
test:{
module: testPlugin,
config:{}
}
};
var contextDefaultStorage={
default: {
module: testPlugin2,
config:{}
},
test:{
module: testPlugin,
config:{}
}
};
afterEach(function() {
sandbox.reset();
Context.clean({allNodes:{}});
return Context.close();
}); });
});
describe('store context',function() {
it('should store local property to external context storage',function() { it('should store local property to external context storage',function() {
Context.init({contextStorage:contextStorage}); Context.init({contextStorage:contextStorage});
return Context.load().then(function(){ return Context.load().then(function(){
@ -385,6 +417,31 @@ describe('context', function() {
}); });
}); });
describe('delete context',function(){
it('should not call delete()', function() {
Context.init({contextStorage:contextDefaultStorage});
return Context.load().then(function(){
Context.get("flowA");
return Context.delete("flowA").then(function(){
stubDelete.called.should.be.false();
stubDelete2.called.should.be.false();
});
});
});
});
describe('clean context',function(){
it('should call clean()', function() {
Context.init({contextStorage:contextDefaultStorage});
return Context.load().then(function(){
return Context.clean({allNodes:{}}).then(function(){
stubClean.calledWithExactly([]).should.be.true();
stubClean2.calledWithExactly([]).should.be.true();
});
});
});
});
describe('key name',function() { describe('key name',function() {
beforeEach(function() { beforeEach(function() {
Context.init({contextStorage:{memory:{module:"memory"}}}); Context.init({contextStorage:{memory:{module:"memory"}}});

View File

@ -31,8 +31,10 @@ describe('localfilesystem',function() {
}); });
afterEach(function() { afterEach(function() {
return context.close().then(function(){ return context.clean([]).then(function(){
return fs.remove(resourcesDir); return context.close().then(function(){
return fs.remove(resourcesDir);
});
}); });
}); });
@ -118,9 +120,39 @@ describe('localfilesystem',function() {
context.get("nodeX","foo").should.eql("abc"); context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc"); context.get("nodeY","foo").should.eql("abc");
context.delete("nodeX"); return context.delete("nodeX").then(function(){
should.not.exist(context.get("nodeX","foo"));
should.exist(context.get("nodeY","foo"));
})
});
});
describe('#clean',function() {
it('should clean unnecessary context',function() {
should.not.exist(context.get("nodeX","foo")); should.not.exist(context.get("nodeX","foo"));
should.exist(context.get("nodeY","foo")); should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc");
return context.clean([]).then(function(){
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
});
it('should not clean active context',function() {
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc");
return context.clean(["nodeX"]).then(function(){
should.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
}); });
}); });
}); });

View File

@ -22,6 +22,13 @@ describe('memory',function() {
beforeEach(function() { beforeEach(function() {
context = Memory({}); context = Memory({});
return context.open();
});
afterEach(function() {
return context.clean([]).then(function(){
return context.close();
});
}); });
describe('#get/set',function() { describe('#get/set',function() {
@ -120,9 +127,39 @@ describe('memory',function() {
context.get("nodeX","foo").should.eql("abc"); context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc"); context.get("nodeY","foo").should.eql("abc");
context.delete("nodeX"); return context.delete("nodeX").then(function(){
should.not.exist(context.get("nodeX","foo"));
should.exist(context.get("nodeY","foo"));
});
});
});
describe('#clean',function() {
it('should clean unnecessary context',function() {
should.not.exist(context.get("nodeX","foo")); should.not.exist(context.get("nodeX","foo"));
should.exist(context.get("nodeY","foo")); should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc");
return context.clean([]).then(function(){
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
});
it('should not clean active context',function() {
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc");
return context.clean(["nodeX"]).then(function(){
should.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
}); });
}); });