mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Add persistable context
and avoid exception when arg is undefined in util/getMessageProperty
This commit is contained in:
		
				
					committed by
					
						
						HirokiUchikawa
					
				
			
			
				
	
			
			
			
						parent
						
							cd44f13171
						
					
				
				
					commit
					771b598c09
				
			@@ -14,20 +14,27 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
var clone = require("clone");
 | 
			
		||||
var when = require("when");
 | 
			
		||||
var util = require("../util");
 | 
			
		||||
var util = require("../../util");
 | 
			
		||||
var log = require("../../log");
 | 
			
		||||
var externalContext = require("./external");
 | 
			
		||||
 | 
			
		||||
var contexts = {};
 | 
			
		||||
var globalContext = null;
 | 
			
		||||
 | 
			
		||||
var re = /^(\$.*?)\.(.+)|^(\$.*)/;
 | 
			
		||||
 | 
			
		||||
function createContext(id,seed) {
 | 
			
		||||
    var flowId = id;
 | 
			
		||||
    var data = seed || {};
 | 
			
		||||
    var obj = seed || {};
 | 
			
		||||
    obj.get = function get(key) {
 | 
			
		||||
 | 
			
		||||
    function get(key) {
 | 
			
		||||
        return util.getMessageProperty(data,key);
 | 
			
		||||
    };
 | 
			
		||||
    obj.set = function set(key, value) {
 | 
			
		||||
    function set(key, value) {
 | 
			
		||||
        util.setMessageProperty(data,key,value);
 | 
			
		||||
    }
 | 
			
		||||
    obj.keys = function() {
 | 
			
		||||
    };
 | 
			
		||||
    function keys() {
 | 
			
		||||
        var keysData = Object.keys(data);
 | 
			
		||||
        if (seed == null) {
 | 
			
		||||
            return keysData;
 | 
			
		||||
@@ -36,13 +43,32 @@ function createContext(id,seed) {
 | 
			
		||||
                return key !== "set" && key !== "get" && key !== "keys";
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    obj.get = function(key) {
 | 
			
		||||
        if(externalContext.canUse(key)) {
 | 
			
		||||
            return externalContext.get(key, flowId);
 | 
			
		||||
        }else{
 | 
			
		||||
            return get(key);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    obj.set = function(key, value) {
 | 
			
		||||
        if(externalContext.canUse(key)) {
 | 
			
		||||
            externalContext.set(key, value, flowId);
 | 
			
		||||
        }else{
 | 
			
		||||
            set(key, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    obj.keys = function(key) {
 | 
			
		||||
        if(externalContext.canUse(key)) {
 | 
			
		||||
            return externalContext.keys(key, flowId);
 | 
			
		||||
        }else{
 | 
			
		||||
            return keys();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var contexts = {};
 | 
			
		||||
var globalContext = null;
 | 
			
		||||
 | 
			
		||||
function getContext(localId,flowId) {
 | 
			
		||||
    var contextId = localId;
 | 
			
		||||
    if (flowId) {
 | 
			
		||||
@@ -61,6 +87,7 @@ function getContext(localId,flowId) {
 | 
			
		||||
    contexts[contextId] = newContext;
 | 
			
		||||
    return newContext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deleteContext(id,flowId) {
 | 
			
		||||
    var contextId = id;
 | 
			
		||||
    if (flowId) {
 | 
			
		||||
@@ -68,6 +95,7 @@ function deleteContext(id,flowId) {
 | 
			
		||||
    }
 | 
			
		||||
    delete contexts[contextId];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function clean(flowConfig) {
 | 
			
		||||
    var activeIds = {};
 | 
			
		||||
    var contextId;
 | 
			
		||||
@@ -81,9 +109,11 @@ function clean(flowConfig) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    init: function(settings) {
 | 
			
		||||
        globalContext = createContext("global",settings.functionGlobalContext || {});
 | 
			
		||||
        externalContext.init(settings);
 | 
			
		||||
    },
 | 
			
		||||
    get: getContext,
 | 
			
		||||
    delete: deleteContext,
 | 
			
		||||
 
 | 
			
		||||
@@ -240,7 +240,7 @@ function getMessageProperty(msg,expr) {
 | 
			
		||||
    var msgPropParts = normalisePropertyExpression(expr);
 | 
			
		||||
    var m;
 | 
			
		||||
    msgPropParts.reduce(function(obj, key) {
 | 
			
		||||
        result = (typeof obj[key] !== "undefined" ? obj[key] : undefined);
 | 
			
		||||
        result = ((typeof obj !== "undefined") && (typeof obj[key] !== "undefined") ? obj[key] : undefined);
 | 
			
		||||
        return result;
 | 
			
		||||
    }, msg);
 | 
			
		||||
    return result;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,12 @@
 | 
			
		||||
 | 
			
		||||
var should = require("should");
 | 
			
		||||
var sinon = require('sinon');
 | 
			
		||||
var Context = require("../../../../red/runtime/nodes/context");
 | 
			
		||||
var path = require('path');
 | 
			
		||||
var fs = require('fs-extra');
 | 
			
		||||
var Context = require("../../../../../red/runtime/nodes/context/index");
 | 
			
		||||
 | 
			
		||||
describe('context', function() {
 | 
			
		||||
    describe('localmemory',function() {
 | 
			
		||||
        beforeEach(function() {
 | 
			
		||||
            Context.init({});
 | 
			
		||||
        });
 | 
			
		||||
@@ -117,7 +120,7 @@ describe('context', function() {
 | 
			
		||||
            Context.delete("1","flowA");
 | 
			
		||||
            context = Context.get("1","flowA");
 | 
			
		||||
            should.not.exist(context.get("foo"));
 | 
			
		||||
    })
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('enumerates context keys', function() {
 | 
			
		||||
            var context = Context.get("1","flowA");
 | 
			
		||||
@@ -135,10 +138,101 @@ describe('context', function() {
 | 
			
		||||
            keys = context.keys();
 | 
			
		||||
            keys.should.have.length(2);
 | 
			
		||||
            keys[1].should.eql("abc");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('external context storage',function() {
 | 
			
		||||
        var testDir = path.join(__dirname,".testUserHome");
 | 
			
		||||
        var context;
 | 
			
		||||
        var stubGet = sinon.stub();
 | 
			
		||||
        var stubSet = sinon.stub();
 | 
			
		||||
        var stubKeys = sinon.stub();
 | 
			
		||||
        var contextStorage={
 | 
			
		||||
                test:{
 | 
			
		||||
                    module: {
 | 
			
		||||
                        init: function() {
 | 
			
		||||
                            return true;
 | 
			
		||||
                        },
 | 
			
		||||
                        get: stubGet,
 | 
			
		||||
                        set: stubSet,
 | 
			
		||||
                        keys: stubKeys,
 | 
			
		||||
                    },
 | 
			
		||||
                    config:{}
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        beforeEach(function() {
 | 
			
		||||
            Context.init({contextStorage:contextStorage});
 | 
			
		||||
            context =  Context.get("1","flow");
 | 
			
		||||
        });
 | 
			
		||||
        afterEach(function(done) {
 | 
			
		||||
            stubGet.reset();
 | 
			
		||||
            stubSet.reset();
 | 
			
		||||
            stubKeys.reset();
 | 
			
		||||
            Context.clean({allNodes:{}});
 | 
			
		||||
            fs.remove(testDir,done);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('if external context storage exists',function() {
 | 
			
		||||
            it('should store local property to external context storage',function() {
 | 
			
		||||
                should.not.exist(context.get("$test.foo"));
 | 
			
		||||
                context.set("$test.foo","test");
 | 
			
		||||
                context.get("$test.foo");
 | 
			
		||||
                context.keys("$test");
 | 
			
		||||
                stubGet.called.should.be.true();
 | 
			
		||||
                stubSet.called.should.be.true();
 | 
			
		||||
                stubKeys.called.should.be.true();
 | 
			
		||||
            });
 | 
			
		||||
            it('should store flow property to external context storage',function() {
 | 
			
		||||
                should.not.exist(context.flow.get("$test.foo"));
 | 
			
		||||
                context.flow.set("$test.foo","test");
 | 
			
		||||
                context.flow.get("$test.foo");
 | 
			
		||||
                context.flow.keys("$test");
 | 
			
		||||
                stubGet.called.should.be.true();
 | 
			
		||||
                stubSet.called.should.be.true();
 | 
			
		||||
                stubKeys.called.should.be.true();
 | 
			
		||||
            });
 | 
			
		||||
            it('should store global property to external context storage',function() {
 | 
			
		||||
                should.not.exist(context.global.get("$test.foo"));
 | 
			
		||||
                context.global.set("$test.foo","test");
 | 
			
		||||
                context.global.get("$test.foo");
 | 
			
		||||
                context.global.keys("$test");
 | 
			
		||||
                stubGet.called.should.be.true();
 | 
			
		||||
                stubSet.called.should.be.true();
 | 
			
		||||
                stubKeys.called.should.be.true();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('if external context storage does not exist',function() {
 | 
			
		||||
            it('should store local property to local memory',function() {
 | 
			
		||||
                should.not.exist(context.flow.get("$nonexist.foo"));
 | 
			
		||||
                context.set("$nonexist.foo","test");
 | 
			
		||||
                context.get("$nonexist.foo").should.eql("test");
 | 
			
		||||
                context.keys("$nonexist").should.have.length(1);
 | 
			
		||||
                stubGet.notCalled.should.be.true();
 | 
			
		||||
                stubSet.notCalled.should.be.true();
 | 
			
		||||
                stubKeys.notCalled.should.be.true();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should store flow property to local memory',function() {
 | 
			
		||||
                should.not.exist(context.flow.get("$nonexist.foo"));
 | 
			
		||||
                context.flow.set("$nonexist.foo","test");
 | 
			
		||||
                context.flow.get("$nonexist.foo").should.eql("test");
 | 
			
		||||
                context.flow.keys("$nonexist").should.have.length(1);
 | 
			
		||||
                stubGet.notCalled.should.be.true();
 | 
			
		||||
                stubSet.notCalled.should.be.true();
 | 
			
		||||
                stubKeys.notCalled.should.be.true();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should store global property to local memory',function() {
 | 
			
		||||
                should.not.exist(context.global.get("$nonexist.foo"));
 | 
			
		||||
                context.global.set("$nonexist.foo","test");
 | 
			
		||||
                context.global.get("$nonexist.foo").should.eql("test");
 | 
			
		||||
                context.global.keys("$nonexist").should.have.length(1);
 | 
			
		||||
                stubGet.notCalled.should.be.true();
 | 
			
		||||
                stubSet.notCalled.should.be.true();
 | 
			
		||||
                stubKeys.notCalled.should.be.true();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user