diff --git a/red/api/comms.js b/red/api/comms.js index de8960c1c..9f443ff0c 100644 --- a/red/api/comms.js +++ b/red/api/comms.js @@ -42,7 +42,6 @@ function init(_server,runtime) { runtime.events.on("node-status",handleStatus); } - function start() { var Tokens = require("./auth/tokens"); var Users = require("./auth/users"); diff --git a/red/api/credentials.js b/red/api/credentials.js index ae3123b3b..e2914df10 100644 --- a/red/api/credentials.js +++ b/red/api/credentials.js @@ -20,7 +20,7 @@ var api; module.exports = { init: function(runtime) { log = runtime.log; - api = runtime.api; + api = runtime.nodes; }, get: function (req, res) { // TODO: It should verify the given node id is of the type specified - diff --git a/red/api/flows.js b/red/api/flows.js index 021b59583..6e783457c 100644 --- a/red/api/flows.js +++ b/red/api/flows.js @@ -21,7 +21,7 @@ var settings; module.exports = { init: function(runtime) { settings = runtime.settings; - redNodes = runtime.api; + redNodes = runtime.nodes; log = runtime.log; }, get: function(req,res) { diff --git a/red/api/index.js b/red/api/index.js index 18f783dbe..9dd495801 100644 --- a/red/api/index.js +++ b/red/api/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2014 IBM Corp. + * Copyright 2014, 2015 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ var i18n; var log; var adminApp; var nodeApp; +var server; var errorHandler = function(err,req,res,next) { if (err.message === "request entity too large") { @@ -49,7 +50,8 @@ var errorHandler = function(err,req,res,next) { res.status(400).json({error:"unexpected_error", message:err.toString()}); }; -function init(server,runtime) { +function init(_server,runtime) { + server = _server; var settings = runtime.settings; i18n = runtime.i18n; log = runtime.log; @@ -150,6 +152,7 @@ module.exports = { comms: { publish: comms.publish }, - adminApp: function() { return adminApp; }, - nodeApp: function() { return nodeApp; } + get adminApp() { return adminApp; }, + get nodeApp() { return nodeApp; }, + get server() { return server; } }; diff --git a/red/api/nodes.js b/red/api/nodes.js index db917255d..4b4cc5477 100644 --- a/red/api/nodes.js +++ b/red/api/nodes.js @@ -24,7 +24,7 @@ var settings; module.exports = { init: function(runtime) { - redNodes = runtime.api; + redNodes = runtime.nodes; log = runtime.log; i18n = runtime.i18n; settings = runtime.settings; diff --git a/red/red.js b/red/red.js index 8e978d5a3..b56323ee3 100644 --- a/red/red.js +++ b/red/red.js @@ -40,29 +40,22 @@ function checkBuild() { module.exports = { init: function(httpServer,userSettings) { - server = httpServer; - if (!userSettings.SKIP_BUILD_CHECK) { checkBuild(); } - runtime.init(userSettings); - if (userSettings.httpAdminRoot !== false || userSettings.httpNodeRoot !== false) { - api.init(server,runtime); - adminApp = api.adminApp(); - nodeApp = api.nodeApp(); - } - if (adminApp === null) { - adminApp = { - get:function(){}, - post: function(){}, - put: function(){}, - delete: function(){} - } - } else { + if (userSettings.httpAdminRoot !== false || userSettings.httpNodeRoot !== false) { + runtime.init(userSettings,api); + api.init(httpServer,runtime); apiEnabled = true; + } else { + runtime.init(userSettings); + apiEnabled = false; } - return runtime.app; + adminApp = runtime.adminApi.adminApp; + nodeApp = runtime.adminApi.nodeApp; + server = runtime.adminApi.server; + return; }, start: function() { return runtime.start().then(function() { @@ -78,7 +71,7 @@ module.exports = { } }) }, - nodes: runtime.api, + nodes: runtime.nodes, log: runtime.log, settings:runtime.settings, util: runtime.util, diff --git a/red/runtime/index.js b/red/runtime/index.js index 7e417882d..b93db1d6d 100644 --- a/red/runtime/index.js +++ b/red/runtime/index.js @@ -27,10 +27,36 @@ var fs = require("fs"); var runtimeMetricInterval = null; -function init(userSettings) { +var stubbedExpressApp = { + get: function() {}, + post: function() {}, + put: function() {}, + delete: function(){} +} +var adminApi = { + library: { + register: function(){} + }, + auth: { + needsPermission: function(){} + }, + comms: { + publish: function(){} + }, + adminApp: stubbedExpressApp, + nodeApp: stubbedExpressApp, + server: {} +} + +function init(userSettings,_adminApi) { userSettings.version = getVersion(); log.init(userSettings); settings.init(userSettings); + if (_adminApi) { + adminApi = _adminApi; + } + redNodes.init(runtime); + } var version; @@ -69,7 +95,6 @@ function start() { } log.info(log._("runtime.version",{component:"Node.js ",version:process.version})); log.info(log._("server.loading")); - redNodes.init(runtime); return redNodes.load().then(function() { var i; @@ -159,6 +184,7 @@ var runtime = module.exports = { settings: settings, storage: storage, events: events, - api: redNodes, - util: require("./util") + nodes: redNodes, + util: require("./util"), + get adminApi() { return adminApi } } diff --git a/red/runtime/log.js b/red/runtime/log.js index 83d767d59..84eb2166f 100644 --- a/red/runtime/log.js +++ b/red/runtime/log.js @@ -50,9 +50,9 @@ var LogHandler = function(settings) { this.logLevel = settings ? levels[settings.level]||levels.info : levels.info; this.metricsOn = settings ? settings.metrics||false : false; this.auditOn = settings ? settings.audit||false : false; - + metricsEnabled = metricsEnabled || this.metricsOn; - + this.handler = (settings && settings.handler) ? settings.handler(settings) : consoleLogger; this.on("log",function(msg) { if (this.shouldReportMessage(msg.level)) { @@ -134,7 +134,7 @@ var log = module.exports = { metric: function() { return metricsEnabled; }, - + audit: function(msg,req) { msg.level = log.AUDIT; if (req) { diff --git a/red/runtime/nodes/flows/Flow.js b/red/runtime/nodes/flows/Flow.js index c85495071..d4b8eaec9 100644 --- a/red/runtime/nodes/flows/Flow.js +++ b/red/runtime/nodes/flows/Flow.js @@ -32,6 +32,7 @@ function Flow(global,flow) { this.start = function(diff) { var node; + var newNode; var id; catchNodeMap = {}; statusNodeMap = {}; @@ -39,7 +40,10 @@ function Flow(global,flow) { if (flow.configs.hasOwnProperty(id)) { node = flow.configs[id]; if (!activeNodes[id]) { - activeNodes[id] = createNode(node.type,node); + newNode = createNode(node.type,node); + if (newNode) { + activeNodes[id] = newNode; + } } } } @@ -57,7 +61,10 @@ function Flow(global,flow) { node = flow.nodes[id]; if (!node.subflow) { if (!activeNodes[id]) { - activeNodes[id] = createNode(node.type,node); + newNode = createNode(node.type,node); + if (newNode) { + activeNodes[id] = newNode; + } } } else { if (!subflowInstanceNodes[id]) { @@ -65,7 +72,9 @@ function Flow(global,flow) { var nodes = createSubflow(flow.subflows[node.subflow]||global.subflows[node.subflow],node,flow.subflows,global.subflows,activeNodes); subflowInstanceNodes[id] = nodes.map(function(n) { return n.id}); for (var i=0;i"; } @@ -107,7 +107,7 @@ describe("nodes api", function() { it('returns node module info', function(done) { initNodes({ - api:{ + nodes:{ getModuleInfo: function(id) { return {"node-red":{name:"node-red"}}[id]; } @@ -127,7 +127,7 @@ describe("nodes api", function() { it('returns 404 for unknown module', function(done) { initNodes({ - api:{ + nodes:{ getModuleInfo: function(id) { return {"node-red":{name:"node-red"}}[id]; } @@ -146,7 +146,7 @@ describe("nodes api", function() { it('returns individual node info', function(done) { initNodes({ - api:{ + nodes:{ getNodeInfo: function(id) { return {"node-red/123":{id:"node-red/123"}}[id]; } @@ -167,7 +167,7 @@ describe("nodes api", function() { it('returns individual node configs', function(done) { initNodes({ - api:{ + nodes:{ getNodeConfig: function(id) { return {"node-red/123":""}[id]; } @@ -191,7 +191,7 @@ describe("nodes api", function() { it('returns 404 for unknown node', function(done) { initNodes({ - api:{ + nodes:{ getNodeInfo: function(id) { return {"node-red/123":{id:"node-red/123"}}[id]; } @@ -247,7 +247,7 @@ describe("nodes api", function() { it('installs the module and returns module info', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return null; }, installModule: function() { return when.resolve({ @@ -275,7 +275,7 @@ describe("nodes api", function() { it('fails the install if already installed', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return {nodes:{id:"123"}}; }, installModule: function() { return when.resolve({id:"123"}); @@ -297,7 +297,7 @@ describe("nodes api", function() { it('fails the install if module error', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return null }, installModule: function() { return when.reject(new Error("test error")); @@ -319,7 +319,7 @@ describe("nodes api", function() { it('fails the install if module not found', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return null }, installModule: function() { var err = new Error("test error"); @@ -362,7 +362,7 @@ describe("nodes api", function() { it('uninstalls the module', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return {nodes:[{id:"123"}]} }, getNodeInfo: function() { return null }, uninstallModule: function() { return when.resolve({id:"123"});} @@ -382,7 +382,7 @@ describe("nodes api", function() { it('fails the uninstall if the module is not installed', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return null }, getNodeInfo: function() { return null } } @@ -401,7 +401,7 @@ describe("nodes api", function() { it('fails the uninstall if the module is not installed', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return {nodes:[{id:"123"}]} }, getNodeInfo: function() { return null }, uninstallModule: function() { return when.reject(new Error("test error"));} @@ -476,7 +476,7 @@ describe("nodes api", function() { it('returns 404 for unknown node', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getNodeInfo: function() { return null } } }); @@ -496,7 +496,7 @@ describe("nodes api", function() { it('returns 404 for unknown module', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function(id) { return null } } }); @@ -516,7 +516,7 @@ describe("nodes api", function() { it('enables disabled node', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getNodeInfo: function() { return {id:"123",enabled: false} }, enableNode: function() { return when.resolve({id:"123",enabled: true,types:['a']}); } } @@ -539,7 +539,7 @@ describe("nodes api", function() { it('disables enabled node', function(done) { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getNodeInfo: function() { return {id:"123",enabled: true} }, disableNode: function() { return when.resolve({id:"123",enabled: false,types:['a']}); } } @@ -566,7 +566,7 @@ describe("nodes api", function() { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getNodeInfo: function() { return {id:"123",enabled: state} }, enableNode: enableNode, disableNode: disableNode @@ -605,7 +605,7 @@ describe("nodes api", function() { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getNodeInfo: function() { return {id:"123",enabled: state, err:"foo"} }, enableNode: enableNode, disableNode: disableNode @@ -652,7 +652,7 @@ describe("nodes api", function() { enableNode.returns(null); initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} }, enableNode: enableNode } @@ -690,7 +690,7 @@ describe("nodes api", function() { disableNode.returns(null); initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} }, disableNode: disableNode } @@ -727,7 +727,7 @@ describe("nodes api", function() { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function() { return {name:"node-red", nodes:[node]}; }, enableNode: enableNode, disableNode: disableNode @@ -774,7 +774,7 @@ describe("nodes api", function() { initNodes({ settings:{available:function(){return true}}, - api:{ + nodes:{ getModuleInfo: function() { return {name:"node-red", nodes:[node]}; }, enableNode: enableNode, disableNode: disableNode diff --git a/test/red/runtime/index_spec.js b/test/red/runtime/index_spec.js index 50ff9b9e2..f2fc29b2e 100644 --- a/test/red/runtime/index_spec.js +++ b/test/red/runtime/index_spec.js @@ -44,16 +44,19 @@ describe("runtime", function() { beforeEach(function() { sinon.stub(log,"init",function() {}); sinon.stub(settings,"init",function() {}); + sinon.stub(redNodes,"init",function() {}) }); afterEach(function() { log.init.restore(); settings.init.restore(); + redNodes.init.restore(); }) it("initialises components", function() { runtime.init({testSettings: true, httpAdminRoot:"/"}); log.init.called.should.be.true; settings.init.called.should.be.true; + redNodes.init.called.should.be.true; }); it("returns version", function() { diff --git a/test/red/runtime/nodes/registry/loader_spec.js b/test/red/runtime/nodes/registry/loader_spec.js index 43887dc5c..3071ff032 100644 --- a/test/red/runtime/nodes/registry/loader_spec.js +++ b/test/red/runtime/nodes/registry/loader_spec.js @@ -44,7 +44,7 @@ describe("red/nodes/registry/loader",function() { }) describe("#init",function() { it("init",function() { - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}}}); localfilesystem.init.called.should.be.true; }); }); @@ -53,7 +53,7 @@ describe("red/nodes/registry/loader",function() { it("load empty set without settings available", function(done) { stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};})); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};})); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); loader.load("foo",true).then(function() { localfilesystem.getNodeFiles.called.should.be.true; localfilesystem.getNodeFiles.lastCall.args[0].should.eql('foo'); @@ -65,7 +65,7 @@ describe("red/nodes/registry/loader",function() { it("load empty set with settings available triggers registery save", function(done) { stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};})); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};})); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.load("foo",true).then(function() { registry.saveNodeList.called.should.be.true; done(); @@ -96,7 +96,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.load().then(function(result) { registry.addNodeSet.called.should.be.true; registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode1"); @@ -143,7 +143,7 @@ describe("red/nodes/registry/loader",function() { // This module isn't already loaded stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.load().then(function(result) { registry.addNodeSet.called.should.be.true; registry.addNodeSet.lastCall.args[0].should.eql("node-red/MultipleNodes1"); @@ -194,7 +194,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.load().then(function(result) { registry.addNodeSet.called.should.be.true; registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode2"); @@ -243,7 +243,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.load().then(function(result) { registry.addNodeSet.called.should.be.true; registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode3"); @@ -290,7 +290,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.load().then(function(result) { registry.addNodeSet.called.should.be.true; registry.addNodeSet.lastCall.args[0].should.eql("node-red/DoesNotExist"); @@ -317,7 +317,7 @@ describe("red/nodes/registry/loader",function() { describe("#addModule",function() { it("throws error if settings unavailable", function() { - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); /*jshint immed: false */ (function(){ loader.addModule("test-module"); @@ -326,7 +326,7 @@ describe("red/nodes/registry/loader",function() { it("returns rejected error if module already loaded", function(done) { stubs.push(sinon.stub(registry,"getModuleInfo",function(){return{}})); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.addModule("test-module").otherwise(function(err) { err.code.should.eql("module_already_loaded"); @@ -338,7 +338,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(localfilesystem,"getModuleFiles",function() { throw new Error("failure"); })); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.addModule("test-module").otherwise(function(err) { err.message.should.eql("failure"); done(); @@ -370,7 +370,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" })); stubs.push(sinon.stub(registry,"addNodeSet", function(){ return })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.addModule("TestNodeModule").then(function(result) { result.should.eql("a node list"); registry.addNodeSet.calledOnce.should.be.true; @@ -420,7 +420,7 @@ describe("red/nodes/registry/loader",function() { stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" })); stubs.push(sinon.stub(registry,"addNodeSet", function(){ return })); stubs.push(sinon.stub(nodes,"registerType")); - loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},version: function() { return "0.12.0"}, settings:{available:function(){return true;}}}); + loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},version: function() { return "0.12.0"}, settings:{available:function(){return true;}}}); loader.addModule("TestNodeModule").then(function(result) { result.should.eql("a node list"); registry.addNodeSet.called.should.be.false;