mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
add external context files
This commit is contained in:
parent
771b598c09
commit
e66b381070
133
red/runtime/nodes/context/external.js
Normal file
133
red/runtime/nodes/context/external.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var when = require("when");
|
||||||
|
var log = require("../../log");
|
||||||
|
|
||||||
|
var re = /^(\$.*?)\.(.+)|^(\$.*)/;
|
||||||
|
var externalContexts;
|
||||||
|
|
||||||
|
function parseKey(key){
|
||||||
|
var keys = null;
|
||||||
|
var temp = re.exec(key);
|
||||||
|
if(temp){
|
||||||
|
keys = [];
|
||||||
|
if(temp[3]){
|
||||||
|
keys[0] = temp[3];
|
||||||
|
keys[1] = null;
|
||||||
|
} else {
|
||||||
|
keys[0] = temp[1];
|
||||||
|
keys[1] = temp[2];
|
||||||
|
}
|
||||||
|
keys[0] = keys[0] === "$" ? "default" : keys[0].substring(1);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasContextStorage(plugin) {
|
||||||
|
return externalContexts.hasOwnProperty(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
var contextModuleInterface ={
|
||||||
|
init: function (settings) {
|
||||||
|
var plugins = settings.contextStorage;
|
||||||
|
externalContexts = {};
|
||||||
|
if (plugins) {
|
||||||
|
for(var pluginName in plugins){
|
||||||
|
var plugin;
|
||||||
|
if(plugins[pluginName].hasOwnProperty("module") && plugins[pluginName].hasOwnProperty("config")) {
|
||||||
|
if(typeof plugins[pluginName].module === "string") {
|
||||||
|
try{
|
||||||
|
plugin = require(plugins[pluginName].module);
|
||||||
|
}catch(err){
|
||||||
|
log.error(err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plugin = plugins[pluginName].module;
|
||||||
|
}
|
||||||
|
plugin.init(plugins[pluginName].config);
|
||||||
|
externalContexts[pluginName] = plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get: function(key, flowId) {
|
||||||
|
var result = parseKey(key);
|
||||||
|
if(!result){
|
||||||
|
throw new Error("Invalid key");
|
||||||
|
}
|
||||||
|
if(hasContextStorage(result[0])){
|
||||||
|
return externalContexts[result[0]].get(result[1], flowId);
|
||||||
|
}else if(hasContextStorage("default")) {
|
||||||
|
// log.warn(result[1] " is got from default context storage");
|
||||||
|
return externalContexts["default"].get(result[1], flowId);
|
||||||
|
}else{
|
||||||
|
throw new Error(result[0] + " is not defined in setting.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
set: function(key, value, flowId) {
|
||||||
|
var result = parseKey(key);
|
||||||
|
if(!result){
|
||||||
|
throw new Error("Invalid key");
|
||||||
|
}
|
||||||
|
if(hasContextStorage(result[0])){
|
||||||
|
externalContexts[result[0]].set(result[1], value, flowId);
|
||||||
|
}else if(hasContextStorage("default")) {
|
||||||
|
// log.warn(result[1] " is set to default context storage");
|
||||||
|
externalContexts["default"].set(result[1], value, flowId);
|
||||||
|
}else{
|
||||||
|
throw new Error(result[0] + " is not defined in setting.js");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keys: function(key, flowId) {
|
||||||
|
var result = parseKey(key);
|
||||||
|
if(!result){
|
||||||
|
throw new Error("Invalid key");
|
||||||
|
}
|
||||||
|
if(hasContextStorage(result[0])){
|
||||||
|
return externalContexts[result[0]].keys(flowId);
|
||||||
|
}else if(hasContextStorage("default")) {
|
||||||
|
// log.warn("keys are got from default context storage");
|
||||||
|
externalContexts["default"].keys(flowId);
|
||||||
|
}else{
|
||||||
|
throw new Error(result[0] + " is not defined in setting.js");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// run: function(command,key,value,flowId) {
|
||||||
|
// //todo: run custom method in plugin
|
||||||
|
// },
|
||||||
|
// close: function(){
|
||||||
|
// //todo: close connections, streams, etc...
|
||||||
|
// },
|
||||||
|
canUse: function(key){
|
||||||
|
var result = parseKey(key);
|
||||||
|
if(!result){
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
if(hasContextStorage(result[0]) || hasContextStorage("default")){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hasContextStorage: hasContextStorage,
|
||||||
|
parseKey: parseKey
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = contextModuleInterface;
|
81
red/runtime/nodes/context/localfilesystem.js
Normal file
81
red/runtime/nodes/context/localfilesystem.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var storage = require('node-persist');
|
||||||
|
var fs = require('fs-extra');
|
||||||
|
var fspath = require("path");
|
||||||
|
|
||||||
|
var configs;
|
||||||
|
var storagePath;
|
||||||
|
var fileStorages;
|
||||||
|
|
||||||
|
function createStorage(path) {
|
||||||
|
var fileStorage = storage.create({dir: fspath.join(storagePath,path)});
|
||||||
|
fileStorage.initSync();
|
||||||
|
fileStorages[path] = fileStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localfilesystem = {
|
||||||
|
init: function(_configs) {
|
||||||
|
configs = _configs;
|
||||||
|
fileStorages = {};
|
||||||
|
if (!configs.dir) {
|
||||||
|
try {
|
||||||
|
fs.statSync(fspath.join(process.env.NODE_RED_HOME,".config.json"));
|
||||||
|
storagePath = fspath.join(process.env.NODE_RED_HOME,"contexts");
|
||||||
|
} catch(err) {
|
||||||
|
try {
|
||||||
|
// Consider compatibility for older versions
|
||||||
|
if (process.env.HOMEPATH) {
|
||||||
|
fs.statSync(fspath.join(process.env.HOMEPATH,".node-red",".config.json"));
|
||||||
|
storagePath = fspath.join(process.env.HOMEPATH,".node-red","contexts");
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
}
|
||||||
|
if (!configs.dir) {
|
||||||
|
storagePath = fspath.join(process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH || process.env.NODE_RED_HOME,".node-red","contexts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
storagePath = configs.dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
stop: function() {
|
||||||
|
return when.resolve();
|
||||||
|
},
|
||||||
|
get: function (key, flowId) {
|
||||||
|
if(!fileStorages[flowId]){
|
||||||
|
createStorage(flowId);
|
||||||
|
}
|
||||||
|
return fileStorages[flowId].getItemSync(key);
|
||||||
|
},
|
||||||
|
|
||||||
|
set: function (key, value, flowId) {
|
||||||
|
if(!fileStorages[flowId]){
|
||||||
|
createStorage(flowId);
|
||||||
|
}
|
||||||
|
fileStorages[flowId].setItemSync(key, value);
|
||||||
|
},
|
||||||
|
keys: function (flowId) {
|
||||||
|
if(!fileStorages[flowId]){
|
||||||
|
createStorage(flowId);
|
||||||
|
}
|
||||||
|
return fileStorages[flowId].keys();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = localfilesystem;
|
222
test/red/runtime/nodes/context/external_spec.js
Normal file
222
test/red/runtime/nodes/context/external_spec.js
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
var should = require("should");
|
||||||
|
var sinon = require('sinon');
|
||||||
|
var external = require("../../../../../red/runtime/nodes/context/external");
|
||||||
|
|
||||||
|
describe("external", function() {
|
||||||
|
var stubModule = {
|
||||||
|
module: {
|
||||||
|
init: function(){},
|
||||||
|
get: function(){},
|
||||||
|
set: function(){},
|
||||||
|
keys: function(){},
|
||||||
|
run: function(){},
|
||||||
|
close: function(){}
|
||||||
|
},
|
||||||
|
config: {}
|
||||||
|
};
|
||||||
|
describe('#init()', function() {
|
||||||
|
it('should load bundle module as default', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
default:{
|
||||||
|
module: "./localfilesystem",
|
||||||
|
config:{}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
external.hasContextStorage("default").should.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load bundle module as localfile', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
localfile:{
|
||||||
|
module: "./localfilesystem",
|
||||||
|
config:{}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
external.hasContextStorage("localfile").should.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not load non-existent module', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
default:{
|
||||||
|
module: "non-existent-module",
|
||||||
|
config:{}
|
||||||
|
}
|
||||||
|
|
||||||
|
}})
|
||||||
|
external.hasContextStorage("default").should.be.false();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load multiple modules', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
default:{
|
||||||
|
module: "./localfilesystem",
|
||||||
|
config:{}
|
||||||
|
},
|
||||||
|
test:{
|
||||||
|
module: {
|
||||||
|
init: function() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config:{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
external.hasContextStorage("default").should.be.true();
|
||||||
|
external.hasContextStorage("test").should.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load multiple modules without non-existent module', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
nonexist:{
|
||||||
|
module: "non-existent-module",
|
||||||
|
config:{}
|
||||||
|
},
|
||||||
|
default:{
|
||||||
|
module: "./localfilesystem",
|
||||||
|
config:{}
|
||||||
|
},
|
||||||
|
test:{
|
||||||
|
module: {
|
||||||
|
init: function() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config:{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
external.hasContextStorage("nonexist").should.be.false();
|
||||||
|
external.hasContextStorage("default").should.be.true();
|
||||||
|
external.hasContextStorage("test").should.be.true();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// describe('#get()', function() {
|
||||||
|
// });
|
||||||
|
|
||||||
|
// describe('#set()', function() {
|
||||||
|
// });
|
||||||
|
|
||||||
|
// describe('#keys()', function() {
|
||||||
|
// });
|
||||||
|
|
||||||
|
// describe('#hasContextStorage()', function() {
|
||||||
|
// });
|
||||||
|
|
||||||
|
describe('#canUse()', function() {
|
||||||
|
it('should return true if specified module is loaded', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
localfilesystem:{
|
||||||
|
module: {name:"test",init: function(){return true}},
|
||||||
|
config: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
external.canUse("$localfilesystem").should.be.true();
|
||||||
|
external.canUse("$localfilesystem.foo").should.be.true();
|
||||||
|
});
|
||||||
|
it('should return false if specified module is not loaded', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
localfilesystem:{
|
||||||
|
module: {name:"test",init: function(){return true}},
|
||||||
|
config: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
external.canUse("$file").should.be.false();
|
||||||
|
external.canUse("$file.foo").should.be.false();
|
||||||
|
});
|
||||||
|
it('should return true if specified module is not loaded but default module is loaded', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
default:{
|
||||||
|
module: {name:"test",init: function(){return true}},
|
||||||
|
config: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
external.canUse("$file").should.be.true();
|
||||||
|
external.canUse("$file.foo").should.be.true();
|
||||||
|
});
|
||||||
|
it('should return false if argument does not contain module name', function() {
|
||||||
|
external.init({
|
||||||
|
contextStorage:{
|
||||||
|
default:{
|
||||||
|
module: {name:"test",init: function(){return true}},
|
||||||
|
config: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
external.canUse("file").should.be.false();
|
||||||
|
external.canUse("file.foo").should.be.false();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#parseKey()', function() {
|
||||||
|
function returnModuleAndKey(input, expectedModule, expectedKey) {
|
||||||
|
var result = external.parseKey(input);
|
||||||
|
result[0].should.eql(expectedModule);
|
||||||
|
result[1].should.eql(expectedKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
function returnModule(input, expectedModule) {
|
||||||
|
var result = external.parseKey(input);
|
||||||
|
result[0].should.eql(expectedModule);
|
||||||
|
should(result[1]).be.null();
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should retrun module and key', function() {
|
||||||
|
returnModuleAndKey("$test.aaa","test","aaa");
|
||||||
|
returnModuleAndKey("$test.aaa.bbb","test","aaa.bbb");
|
||||||
|
returnModuleAndKey("$1.234","1","234");
|
||||||
|
returnModuleAndKey("$$test.foo","$test","foo");
|
||||||
|
returnModuleAndKey("$test.$foo","test","$foo");
|
||||||
|
returnModuleAndKey("$test.$foo.$bar","test","$foo.$bar");
|
||||||
|
returnModuleAndKey("$test..foo","test",".foo");
|
||||||
|
returnModuleAndKey("$test..","test",".");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrun only module', function() {
|
||||||
|
returnModule("$test","test",null);
|
||||||
|
returnModule("$1","1",null);
|
||||||
|
returnModule("$$test","$test",null);
|
||||||
|
returnModule("$test.","test.",null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrun module as default', function() {
|
||||||
|
returnModuleAndKey("$default.foo","default","foo");
|
||||||
|
returnModuleAndKey("$.foo","default","foo");
|
||||||
|
returnModule("$default","default");
|
||||||
|
returnModule("$","default");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrun null', function() {
|
||||||
|
should(external.parseKey("test.aaa")).be.null();
|
||||||
|
should(external.parseKey("test")).be.null();
|
||||||
|
should(external.parseKey(null)).be.null();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user