mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge pull request #498 from anna2130/nr-cli-enhancements
nr-cli enhancements - server side api
This commit is contained in:
		| @@ -19,7 +19,6 @@ var util = require('util'); | |||||||
|  |  | ||||||
| var ui = require("./ui"); | var ui = require("./ui"); | ||||||
| var nodes = require("./nodes"); | var nodes = require("./nodes"); | ||||||
| var plugins = require("./plugins"); |  | ||||||
| var flows = require("./flows"); | var flows = require("./flows"); | ||||||
| var library = require("./library"); | var library = require("./library"); | ||||||
|  |  | ||||||
| @@ -52,20 +51,18 @@ function init(adminApp) { | |||||||
|     adminApp.get("/nodes",nodes.getAll); |     adminApp.get("/nodes",nodes.getAll); | ||||||
|     adminApp.post("/nodes",nodes.post); |     adminApp.post("/nodes",nodes.post); | ||||||
|  |  | ||||||
|     adminApp.get("/nodes/:id",nodes.get); |     adminApp.get("/nodes/:mod",nodes.getModule); | ||||||
|     adminApp.put("/nodes/:id",nodes.put); |     adminApp.put("/nodes/:mod",nodes.putModule); | ||||||
|     adminApp.delete("/nodes/:id",nodes.delete); |     adminApp.delete("/nodes/:mod",nodes.delete); | ||||||
|  |  | ||||||
|     // Plugins |     adminApp.get("/nodes/:mod/:set",nodes.getSet); | ||||||
|     adminApp.get("/plugins",plugins.getAll); |     adminApp.put("/nodes/:mod/:set",nodes.putSet); | ||||||
|     adminApp.get("/plugins/:id",plugins.get); |  | ||||||
|  |  | ||||||
|     // Library |     // Library | ||||||
|     adminApp.post(new RegExp("/library/flows\/(.*)"),library.post); |     adminApp.post(new RegExp("/library/flows\/(.*)"),library.post); | ||||||
|     adminApp.get("/library/flows",library.getAll); |     adminApp.get("/library/flows",library.getAll); | ||||||
|     adminApp.get(new RegExp("/library/flows\/(.*)"),library.get); |     adminApp.get(new RegExp("/library/flows\/(.*)"),library.get); | ||||||
|  |  | ||||||
|  |  | ||||||
|     // Error Handler |     // Error Handler | ||||||
|     adminApp.use(errorHandler); |     adminApp.use(errorHandler); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ module.exports = { | |||||||
|             res.send(redNodes.getNodeConfigs()); |             res.send(redNodes.getNodeConfigs()); | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     post: function(req,res) { |     post: function(req,res) { | ||||||
|         if (!settings.available()) { |         if (!settings.available()) { | ||||||
|             res.send(400,new Error("Settings unavailable").toString()); |             res.send(400,new Error("Settings unavailable").toString()); | ||||||
| @@ -55,7 +56,7 @@ module.exports = { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         promise.then(function(info) { |         promise.then(function(info) { | ||||||
|             res.json(info); |             res.json(redNodes.getModuleInfo(node.module)); | ||||||
|         }).otherwise(function(err) { |         }).otherwise(function(err) { | ||||||
|             if (err.code === 404) { |             if (err.code === 404) { | ||||||
|                 res.send(404); |                 res.send(404); | ||||||
| @@ -70,25 +71,19 @@ module.exports = { | |||||||
|             res.send(400,new Error("Settings unavailable").toString()); |             res.send(400,new Error("Settings unavailable").toString()); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         var id = req.params.id; |         var mod = req.params.mod; | ||||||
|         var removedNodes = []; |  | ||||||
|         try { |         try { | ||||||
|             var node = redNodes.getNodeInfo(id); |  | ||||||
|             var promise = null; |             var promise = null; | ||||||
|             if (!node) { |             var module = redNodes.getNodeModuleInfo(mod); | ||||||
|                 var module = redNodes.getNodeModuleInfo(id); |  | ||||||
|             if (!module) { |             if (!module) { | ||||||
|                 res.send(404); |                 res.send(404); | ||||||
|                 return; |                 return; | ||||||
|             } else { |             } else { | ||||||
|                     promise = server.uninstallModule(id); |                 promise = server.uninstallModule(mod); | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 promise = when.resolve([redNodes.removeNode(id)]).then(server.reportRemovedModules); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             promise.then(function(removedNodes) { |             promise.then(function() { | ||||||
|                 res.json(removedNodes); |                 res.send(204); | ||||||
|             }).otherwise(function(err) { |             }).otherwise(function(err) { | ||||||
|                 res.send(400,err.toString()); |                 res.send(400,err.toString()); | ||||||
|             }); |             }); | ||||||
| @@ -97,10 +92,10 @@ module.exports = { | |||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     get: function(req,res) { |     getSet: function(req,res) { | ||||||
|         var id = req.params.id; |         var id = req.params.mod + "/" + req.params.set; | ||||||
|         var result = null; |         var result = null; | ||||||
|         if (req.get("accept") == "application/json") { |         if (req.get("accept") === "application/json") { | ||||||
|             result = redNodes.getNodeInfo(id); |             result = redNodes.getNodeInfo(id); | ||||||
|         } else { |         } else { | ||||||
|             result = redNodes.getNodeConfig(id); |             result = redNodes.getNodeConfig(id); | ||||||
| @@ -112,7 +107,17 @@ module.exports = { | |||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     put: function(req,res) { |     getModule: function(req,res) { | ||||||
|  |         var module = req.params.mod; | ||||||
|  |         var result = redNodes.getModuleInfo(module); | ||||||
|  |         if (result) { | ||||||
|  |             res.send(result); | ||||||
|  |         } else { | ||||||
|  |             res.send(404); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     putSet: function(req,res) { | ||||||
|         if (!settings.available()) { |         if (!settings.available()) { | ||||||
|             res.send(400,new Error("Settings unavailable").toString()); |             res.send(400,new Error("Settings unavailable").toString()); | ||||||
|             return; |             return; | ||||||
| @@ -123,9 +128,9 @@ module.exports = { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         try { |         try { | ||||||
|             var info; |             var id = req.params.mod+"/"+req.params.set; | ||||||
|             var id = req.params.id; |  | ||||||
|             var node = redNodes.getNodeInfo(id); |             var node = redNodes.getNodeInfo(id); | ||||||
|  |             var info; | ||||||
|             if (!node) { |             if (!node) { | ||||||
|                 res.send(404); |                 res.send(404); | ||||||
|             } else if (!node.err && node.enabled === body.enabled) { |             } else if (!node.err && node.enabled === body.enabled) { | ||||||
| @@ -151,5 +156,50 @@ module.exports = { | |||||||
|         } catch(err) { |         } catch(err) { | ||||||
|             res.send(400,err.toString()); |             res.send(400,err.toString()); | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     putModule: function(req,res) { | ||||||
|  |         if (!settings.available()) { | ||||||
|  |             res.send(400,new Error("Settings unavailable").toString()); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         var body = req.body; | ||||||
|  |         if (!body.hasOwnProperty("enabled")) { | ||||||
|  |             res.send(400,"Invalid request"); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         try { | ||||||
|  |             var mod = req.params.mod; | ||||||
|  |             var module = redNodes.getModuleInfo(mod); | ||||||
|  |             if (!module) { | ||||||
|  |                 res.send(404); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             var nodes = module.nodes; | ||||||
|  |             for (var i = 0; i < nodes.length; ++i) { | ||||||
|  |                 var node = nodes[i]; | ||||||
|  |                 var info; | ||||||
|  |                 if (node.err || node.enabled !== body.enabled) { | ||||||
|  |                     if (body.enabled) { | ||||||
|  |                         info = redNodes.enableNode(node.id); | ||||||
|  |                     } else { | ||||||
|  |                         info = redNodes.disableNode(node.id); | ||||||
|  |                     } | ||||||
|  |                     if (info.enabled === body.enabled && !info.err) { | ||||||
|  |                         comms.publish("node/"+(body.enabled?"enabled":"disabled"),info,false); | ||||||
|  |                         util.log("[red] "+(body.enabled?"Enabled":"Disabled")+" node types:"); | ||||||
|  |                         for (var j = 0; j < info.types.length; j++) { | ||||||
|  |                             util.log("[red] - " + info.types[j]); | ||||||
|  |                         } | ||||||
|  |                     } else if (body.enabled && info.err) { | ||||||
|  |                         util.log("[red] Failed to enable node:"); | ||||||
|  |                         util.log("[red] - "+info.name+" : "+info.err); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|  |             res.json(redNodes.getModuleInfo(mod)); | ||||||
|  |         } catch(err) { | ||||||
|  |             res.send(400,err.toString()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|   | |||||||
| @@ -1,32 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 redNodes = require("../nodes"); |  | ||||||
|  |  | ||||||
| module.exports = { |  | ||||||
|     getAll: function(req,res) { |  | ||||||
|         res.json(redNodes.getPluginList()); |  | ||||||
|     }, |  | ||||||
|     get: function(req,res) { |  | ||||||
|         var id = req.params.id; |  | ||||||
|         var result = redNodes.getPluginInfo(id); |  | ||||||
|         if (result) { |  | ||||||
|             res.send(result); |  | ||||||
|         } else { |  | ||||||
|             res.send(404); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 path = require("path"); |  | ||||||
| var fs = require("fs"); |  | ||||||
|  |  | ||||||
| var userHome = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE; |  | ||||||
|  |  | ||||||
| var configDir = path.join(userHome,".nodered"); |  | ||||||
| var configFile = path.join(configDir,"config.json"); |  | ||||||
|  |  | ||||||
| var config; |  | ||||||
|  |  | ||||||
| function load() { |  | ||||||
|     if (config == null) { |  | ||||||
|         try { |  | ||||||
|             config = JSON.parse(fs.readFileSync(configFile)); |  | ||||||
|         } catch(err) { |  | ||||||
|             config = {}; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function save() { |  | ||||||
|     try { |  | ||||||
|         fs.mkdirSync(configDir); |  | ||||||
|     } catch(err) { |  | ||||||
|         if (err.code != "EEXIST") { |  | ||||||
|             throw err; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     fs.writeFileSync(configFile,JSON.stringify(config,null,4)); |  | ||||||
| } |  | ||||||
| module.exports = { |  | ||||||
|     unload: function() { |  | ||||||
|         config = null; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| module.exports.__defineGetter__('target',function() { load(); return config.target|| "http://localhost:1880" }); |  | ||||||
| module.exports.__defineSetter__('target',function(v) { load(); config.target = v; save();}); |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 request = require("request"); |  | ||||||
| var config = require("./config"); |  | ||||||
|  |  | ||||||
| module.exports = function(path, options) { |  | ||||||
|     var basePath = config.target; |  | ||||||
|     return when.promise(function(resolve,reject) { |  | ||||||
|         options.headers = options.headers||{}; |  | ||||||
|         options.headers['Accept'] = 'application/json'; |  | ||||||
|         if (options.method == 'PUT' || options.method == "POST") { |  | ||||||
|             options.headers['content-type'] = 'application/json'; |  | ||||||
|         } |  | ||||||
|         options.url = basePath+path; |  | ||||||
|          |  | ||||||
|         // Pull out the request function so we can stub it in the tests |  | ||||||
|         var requestFunc = request.get; |  | ||||||
|          |  | ||||||
|         if (options.method == 'PUT') { |  | ||||||
|             requestFunc = request.put; |  | ||||||
|         } else if (options.method == 'POST') { |  | ||||||
|             requestFunc = request.post; |  | ||||||
|         } else if (options.method == 'DELETE') { |  | ||||||
|             requestFunc = request.del; |  | ||||||
|         } |  | ||||||
|         requestFunc(options, function(error,response,body) { |  | ||||||
|             if (!error && response.statusCode == 200) { |  | ||||||
|                 resolve(JSON.parse(body)); |  | ||||||
|             } else if (error) { |  | ||||||
|                 reject(error.toString()); |  | ||||||
|             } else { |  | ||||||
|                 reject(response.statusCode+": "+body) |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     }); |  | ||||||
| } |  | ||||||
| @@ -1,151 +0,0 @@ | |||||||
| #!/usr/bin/env node |  | ||||||
| ;(function() { |  | ||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 util = require("util"); |  | ||||||
| var request = require("request"); |  | ||||||
| var colors = require('colors'); |  | ||||||
| var apiRequest = require("./lib/request"); |  | ||||||
| var config = require("./lib/config"); |  | ||||||
|  |  | ||||||
| var commands = { |  | ||||||
|     "target": function() { |  | ||||||
|         var target = process.argv[3]; |  | ||||||
|         if (target) { |  | ||||||
|             if (!/^https?:\/\/.+/.test(target)) { |  | ||||||
|                 console.warn("Invalid target url"); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (target.slice(-1) == "/") { |  | ||||||
|                 target = target.slice(0,target.length-1); |  | ||||||
|             } |  | ||||||
|             var oldTarget = config.target; |  | ||||||
|             config.target = target; |  | ||||||
|         } else { |  | ||||||
|             console.log("Target: ".yellow+config.target); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|     }, |  | ||||||
|     "nodes": function() { |  | ||||||
|         apiRequest('/nodes',{}).then(logNodeList).otherwise(logFailure); |  | ||||||
|     }, |  | ||||||
|     "node": function() { |  | ||||||
|         apiRequest('/nodes/'+process.argv[3],{}).then(logNodeList).otherwise(logFailure); |  | ||||||
|     }, |  | ||||||
|     "enable-node": function() { |  | ||||||
|         apiRequest('/nodes/'+process.argv[3],{ |  | ||||||
|             method: "PUT", |  | ||||||
|             body: JSON.stringify({enabled:true}) |  | ||||||
|         }).then(logNodeList).otherwise(logFailure); |  | ||||||
|     }, |  | ||||||
|     "disable-node": function() { |  | ||||||
|         apiRequest('/nodes/'+process.argv[3],{ |  | ||||||
|             method: "PUT", |  | ||||||
|             body: JSON.stringify({enabled:false}) |  | ||||||
|         }).then(logNodeList).otherwise(logFailure); |  | ||||||
|     }, |  | ||||||
|     "install": function() { |  | ||||||
|         apiRequest('/nodes',{ |  | ||||||
|             method: "POST", |  | ||||||
|             body: JSON.stringify({module:process.argv[3]}) |  | ||||||
|         }).then(logNodeList).otherwise(logFailure); |  | ||||||
|     }, |  | ||||||
|     "remove": function() { |  | ||||||
|         apiRequest('/nodes/'+process.argv[3],{ |  | ||||||
|             method: "DELETE" |  | ||||||
|         }).then(logNodeList).otherwise(logFailure); |  | ||||||
|     }, |  | ||||||
|     "search": function() { |  | ||||||
|         var options = { |  | ||||||
|             method: "GET", |  | ||||||
|             url: 'https://registry.npmjs.org/-/_view/byKeyword?startkey=["node-red"]&endkey=["node-red",{}]&group_level=3' , |  | ||||||
|             headers: { |  | ||||||
|                 'Accept': 'application/json', |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|         request(options, function (error, response, body) { |  | ||||||
|             if (!error && response.statusCode == 200) { |  | ||||||
|                 var info = (JSON.parse(body)).rows; |  | ||||||
|                 var filter = null; |  | ||||||
|                 if (process.argv[3]) { |  | ||||||
|                     filter = new RegExp(process.argv[3]); |  | ||||||
|                 } |  | ||||||
|                 for (var i=0;i<info.length;i++) { |  | ||||||
|                     var n = info[i]; |  | ||||||
|                     if (!filter || filter.test(n.key[1]) || filter.test(n.key[2])) { |  | ||||||
|                         console.log(n.key[1] + (" - "+ n.key[2]).grey); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } else if (error) { |  | ||||||
|                 console.log(error.toString().red); |  | ||||||
|             } else { |  | ||||||
|                 console.log((response.statusCode+": "+body).red); |  | ||||||
|             } |  | ||||||
|         });    |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function logNodeList(nodes) { |  | ||||||
|     if (!util.isArray(nodes)) { |  | ||||||
|         nodes = [nodes]; |  | ||||||
|     } |  | ||||||
|     for (var i=0;i<nodes.length;i++) { |  | ||||||
|         var n = nodes[i]; |  | ||||||
|         console.log(formatNodeInfo(n)) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function logFailure(msg) { |  | ||||||
|     console.log(msg.red); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function formatBoolean(v,c) { |  | ||||||
|     if (v) { |  | ||||||
|         return ("["+c+"]"); |  | ||||||
|     } else { |  | ||||||
|         return ("[ ]"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function formatNodeInfo(n) { |  | ||||||
|     var inError = n.hasOwnProperty("err"); |  | ||||||
|      |  | ||||||
|     var str = formatBoolean(n.enabled,"X")+formatBoolean(n.loaded,"L")+" "; |  | ||||||
|     str += n.id; |  | ||||||
|     if (n.enabled && n.loaded) { |  | ||||||
|         str = str.green; |  | ||||||
|     } else if (n.enabled && n.err) { |  | ||||||
|         str = str.red; |  | ||||||
|     } else { |  | ||||||
|         str = str.yellow; |  | ||||||
|     } |  | ||||||
|     if (n.module) { |  | ||||||
|         str += " ["+n.module+"]"; |  | ||||||
|     } |  | ||||||
|     str += " "+n.types.join(", "); |  | ||||||
|     if (n.err) { |  | ||||||
|         str+=" "+n.err.red; |  | ||||||
|     } |  | ||||||
|     return str; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (commands[process.argv[2]]) { |  | ||||||
|     commands[process.argv[2]].call(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| })(); |  | ||||||
| @@ -55,7 +55,7 @@ function checkTypeInUse(id) { | |||||||
|     var nodeInfo = registry.getNodeInfo(id); |     var nodeInfo = registry.getNodeInfo(id); | ||||||
|     if (!nodeInfo) { |     if (!nodeInfo) { | ||||||
|         throw new Error("Unrecognised id: "+id); |         throw new Error("Unrecognised id: "+id); | ||||||
|     } |     } else { | ||||||
|         var inUse = {}; |         var inUse = {}; | ||||||
|         flows.each(function(n) { |         flows.each(function(n) { | ||||||
|             inUse[n.type] = (inUse[n.type]||0)+1; |             inUse[n.type] = (inUse[n.type]||0)+1; | ||||||
| @@ -71,6 +71,7 @@ function checkTypeInUse(id) { | |||||||
|             throw new Error("Type in use: "+msg); |             throw new Error("Type in use: "+msg); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| function removeNode(id) { | function removeNode(id) { | ||||||
|     checkTypeInUse(id); |     checkTypeInUse(id); | ||||||
| @@ -79,12 +80,15 @@ function removeNode(id) { | |||||||
|  |  | ||||||
| function removeModule(module) { | function removeModule(module) { | ||||||
|     var info = registry.getNodeModuleInfo(module); |     var info = registry.getNodeModuleInfo(module); | ||||||
|     for (var i=0;i<info.nodes.length;i++) { |     if (!info) { | ||||||
|         checkTypeInUse(info.nodes[i]); |         throw new Error("Unrecognised module: "+module); | ||||||
|  |     } else { | ||||||
|  |         for (var i=0;i<info.length;i++) { | ||||||
|  |             checkTypeInUse(module+"/"+info[i]); | ||||||
|         } |         } | ||||||
|         return registry.removeModule(module); |         return registry.removeModule(module); | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| function disableNode(id) { | function disableNode(id) { | ||||||
|     checkTypeInUse(id); |     checkTypeInUse(id); | ||||||
| @@ -112,15 +116,20 @@ module.exports = { | |||||||
|     // Node type registry |     // Node type registry | ||||||
|     registerType: registerType, |     registerType: registerType, | ||||||
|     getType: registry.get, |     getType: registry.get, | ||||||
|  |  | ||||||
|     getNodeInfo: registry.getNodeInfo, |     getNodeInfo: registry.getNodeInfo, | ||||||
|     getNodeModuleInfo: registry.getNodeModuleInfo, |  | ||||||
|     getPluginInfo: registry.getPluginInfo, |  | ||||||
|     getNodeList: registry.getNodeList, |     getNodeList: registry.getNodeList, | ||||||
|     getPluginList: registry.getPluginList, |  | ||||||
|  |     getNodeModuleInfo: registry.getNodeModuleInfo, | ||||||
|  |  | ||||||
|  |     getModuleInfo: registry.getModuleInfo, | ||||||
|  |     getModuleList: registry.getModuleList, | ||||||
|  |  | ||||||
|     getNodeConfigs: registry.getNodeConfigs, |     getNodeConfigs: registry.getNodeConfigs, | ||||||
|     getNodeConfig: registry.getNodeConfig, |     getNodeConfig: registry.getNodeConfig, | ||||||
|  |  | ||||||
|     clearRegistry: registry.clear, |     clearRegistry: registry.clear, | ||||||
|     cleanNodeList: registry.cleanNodeList, |     cleanModuleList: registry.cleanModuleList, | ||||||
|  |  | ||||||
|     // Flow handling |     // Flow handling | ||||||
|     loadFlows: flows.load, |     loadFlows: flows.load, | ||||||
|   | |||||||
| @@ -46,31 +46,48 @@ function filterNodeInfo(n) { | |||||||
|     return r; |     return r; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getModule(id) { | ||||||
|  |     return id.split("/")[0]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getNode(id) { | ||||||
|  |     return id.split("/")[1]; | ||||||
|  | } | ||||||
|  |  | ||||||
| var registry = (function() { | var registry = (function() { | ||||||
|     var nodeConfigCache = null; |     var nodeConfigCache = null; | ||||||
|     var nodeConfigs = {}; |     var moduleConfigs = {}; | ||||||
|     var nodeList = []; |     var nodeList = []; | ||||||
|     var nodeConstructors = {}; |     var nodeConstructors = {}; | ||||||
|     var nodeTypeToId = {}; |     var nodeTypeToId = {}; | ||||||
|     var nodeModules = {}; |     var moduleNodes = {}; | ||||||
|  |  | ||||||
|     function saveNodeList() { |     function saveNodeList() { | ||||||
|         var nodeList = {}; |         var moduleList = {}; | ||||||
|  |  | ||||||
|         for (var i in nodeConfigs) { |         for (var module in moduleConfigs) { | ||||||
|             if (nodeConfigs.hasOwnProperty(i)) { |             if (moduleConfigs.hasOwnProperty(module)) { | ||||||
|                 var nodeConfig = nodeConfigs[i]; |                 if (!moduleList[module]) { | ||||||
|                 var n = filterNodeInfo(nodeConfig); |                     moduleList[module] = {}; | ||||||
|                 n.file = nodeConfig.file; |                     moduleList[module].name = module; | ||||||
|  |                     moduleList[module].nodes = {}; | ||||||
|  |                 } | ||||||
|  |                 var nodes = moduleConfigs[module].nodes; | ||||||
|  |                 for(var node in nodes) { | ||||||
|  |                     if (nodes.hasOwnProperty(node)) { | ||||||
|  |                         var config = nodes[node]; | ||||||
|  |                         var n = filterNodeInfo(config); | ||||||
|                         delete n.loaded; |                         delete n.loaded; | ||||||
|                         delete n.err; |                         delete n.err; | ||||||
|                         delete n.file; |                         delete n.file; | ||||||
|                         delete n.id; |                         delete n.id; | ||||||
|                 nodeList[i] = n; |                         moduleList[module].nodes[node] = n; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (settings.available()) { |         if (settings.available()) { | ||||||
|             return settings.set("nodes",nodeList); |             return settings.set("modules",moduleList); | ||||||
|         } else { |         } else { | ||||||
|             return when.reject("Settings unavailable"); |             return when.reject("Settings unavailable"); | ||||||
|         } |         } | ||||||
| @@ -79,45 +96,47 @@ var registry = (function() { | |||||||
|     return { |     return { | ||||||
|         init: function() { |         init: function() { | ||||||
|             if (settings.available()) { |             if (settings.available()) { | ||||||
|                 nodeConfigs = settings.get("nodes")||{}; |                 moduleConfigs = settings.get("modules")||{}; | ||||||
|                 // Restore the node id property to individual entries |  | ||||||
|                 for (var id in nodeConfigs) { |  | ||||||
|                     if (nodeConfigs.hasOwnProperty(id)) { |  | ||||||
|                         nodeConfigs[id].id = id; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } else { |             } else { | ||||||
|                 nodeConfigs = {}; |                 moduleConfigs = {}; | ||||||
|             } |             } | ||||||
|             nodeModules = {}; |             moduleNodes = {}; | ||||||
|             nodeTypeToId = {}; |             nodeTypeToId = {}; | ||||||
|             nodeConstructors = {}; |             nodeConstructors = {}; | ||||||
|             nodeList = []; |             nodeList = []; | ||||||
|             nodeConfigCache = null; |             nodeConfigCache = null; | ||||||
|         }, |         }, | ||||||
|  |         addNodeSet: function(id,set,version) { | ||||||
|         addNodeSet: function(id,set) { |  | ||||||
|             if (!set.err) { |             if (!set.err) { | ||||||
|                 set.types.forEach(function(t) { |                 set.types.forEach(function(t) { | ||||||
|                     nodeTypeToId[t] = id; |                     nodeTypeToId[t] = id; | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (set.module) { |             moduleNodes[set.module] = moduleNodes[set.module]||[]; | ||||||
|                 nodeModules[set.module] = nodeModules[set.module]||{nodes:[]}; |             moduleNodes[set.module].push(set.name); | ||||||
|                 nodeModules[set.module].nodes.push(id); |  | ||||||
|  |             if (!moduleConfigs[set.module]) { | ||||||
|  |                 moduleConfigs[set.module] = { | ||||||
|  |                     name: set.module, | ||||||
|  |                     nodes: {} | ||||||
|  |                 }; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             nodeConfigs[id] = set; |             if (version) { | ||||||
|  |                 moduleConfigs[set.module].version = version; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             moduleConfigs[set.module].nodes[set.name] = set; | ||||||
|             nodeList.push(id); |             nodeList.push(id); | ||||||
|             nodeConfigCache = null; |             nodeConfigCache = null; | ||||||
|         }, |         }, | ||||||
|         removeNode: function(id) { |         removeNode: function(id) { | ||||||
|             var config = nodeConfigs[id]; |             var config = moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|             if (!config) { |             if (!config) { | ||||||
|                 throw new Error("Unrecognised id: "+id); |                 throw new Error("Unrecognised id: "+id); | ||||||
|             } |             } | ||||||
|             delete nodeConfigs[id]; |             delete moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|             var i = nodeList.indexOf(id); |             var i = nodeList.indexOf(id); | ||||||
|             if (i > -1) { |             if (i > -1) { | ||||||
|                 nodeList.splice(i,1); |                 nodeList.splice(i,1); | ||||||
| @@ -135,62 +154,81 @@ var registry = (function() { | |||||||
|             if (!settings.available()) { |             if (!settings.available()) { | ||||||
|                 throw new Error("Settings unavailable"); |                 throw new Error("Settings unavailable"); | ||||||
|             } |             } | ||||||
|             var nodes = nodeModules[module]; |             var nodes = moduleNodes[module]; | ||||||
|             if (!nodes) { |             if (!nodes) { | ||||||
|                 throw new Error("Unrecognised module: "+module); |                 throw new Error("Unrecognised module: "+module); | ||||||
|             } |             } | ||||||
|             var infoList = []; |             var infoList = []; | ||||||
|             for (var i=0;i<nodes.nodes.length;i++) { |             for (var i=0;i<nodes.length;i++) { | ||||||
|                 infoList.push(registry.removeNode(nodes.nodes[i])); |                 infoList.push(registry.removeNode(module+"/"+nodes[i])); | ||||||
|             } |             } | ||||||
|             delete nodeModules[module]; |             delete moduleNodes[module]; | ||||||
|             saveNodeList(); |             saveNodeList(); | ||||||
|             return infoList; |             return infoList; | ||||||
|         }, |         }, | ||||||
|         getNodeInfo: function(typeOrId) { |         getNodeInfo: function(typeOrId) { | ||||||
|  |             var id = typeOrId; | ||||||
|             if (nodeTypeToId[typeOrId]) { |             if (nodeTypeToId[typeOrId]) { | ||||||
|                 return filterNodeInfo(nodeConfigs[nodeTypeToId[typeOrId]]); |                 id = nodeTypeToId[typeOrId]; | ||||||
|             } else if (nodeConfigs[typeOrId]) { |             } | ||||||
|                 return filterNodeInfo(nodeConfigs[typeOrId]); |             if (id) { | ||||||
|  |                 var module = moduleConfigs[getModule(id)]; | ||||||
|  |                 if (module) { | ||||||
|  |                     var config = module.nodes[getNode(id)]; | ||||||
|  |                     if (config) { | ||||||
|  |                         return filterNodeInfo(config); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             return null; |             return null; | ||||||
|         }, |         }, | ||||||
|         getNodeList: function() { |         getNodeList: function() { | ||||||
|             var list = []; |             var list = []; | ||||||
|             for (var id in nodeConfigs) { |             for (var module in moduleConfigs) { | ||||||
|                 if (nodeConfigs.hasOwnProperty(id)) { |                 if (moduleConfigs.hasOwnProperty(module)) { | ||||||
|                     list.push(filterNodeInfo(nodeConfigs[id])); |                     var nodes = moduleConfigs[module].nodes; | ||||||
|  |                     for (var node in nodes) { | ||||||
|  |                         if (nodes.hasOwnProperty(node)) { | ||||||
|  |                             list.push(filterNodeInfo(nodes[node])); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return list; |             return list; | ||||||
|         }, |         }, | ||||||
|         getPluginList: function() { |         getModuleList: function() { | ||||||
|             var list = []; |             var list = []; | ||||||
|             for (var plugin in nodeModules) { |             for (var module in moduleNodes) { | ||||||
|                 if (nodeModules.hasOwnProperty(plugin)) { |                 if (moduleNodes.hasOwnProperty(module)) { | ||||||
|                     var nodes = nodeModules[plugin].nodes; |                     var nodes = moduleNodes[module]; | ||||||
|                     var m = { |                     var m = { | ||||||
|                         name: plugin, |                         name: module, | ||||||
|  |                         version: moduleConfigs[module].version, | ||||||
|                         nodes: [] |                         nodes: [] | ||||||
|                     }; |                     }; | ||||||
|                     for (var i = 0; i < nodes.length; ++i) { |                     for (var i = 0; i < nodes.length; ++i) { | ||||||
|                         m.nodes.push(filterNodeInfo(nodeConfigs[nodes[i]])); |                         m.nodes.push(filterNodeInfo(moduleConfigs[module].nodes[nodes[i]])); | ||||||
|                     } |                     } | ||||||
|                     list.push(m); |                     list.push(m); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return list; |             return list; | ||||||
|         }, |         }, | ||||||
|         getPluginInfo: function(plugin) { |         getModuleInfo: function(module) { | ||||||
|             var nodes = nodeModules[plugin].nodes; |             if (moduleNodes[module]) { | ||||||
|  |                 var nodes = moduleNodes[module]; | ||||||
|                 var m = { |                 var m = { | ||||||
|                 name: plugin, |                     name: module, | ||||||
|  |                     version: moduleConfigs[module].version, | ||||||
|                     nodes: [] |                     nodes: [] | ||||||
|                 }; |                 }; | ||||||
|                 for (var i = 0; i < nodes.length; ++i) { |                 for (var i = 0; i < nodes.length; ++i) { | ||||||
|                 m.nodes.push(filterNodeInfo(nodeConfigs[nodes[i]])); |                     m.nodes.push(filterNodeInfo(moduleConfigs[module].nodes[nodes[i]])); | ||||||
|                 } |                 } | ||||||
|                 return m; |                 return m; | ||||||
|  |             } else { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|         registerNodeConstructor: function(type,constructor) { |         registerNodeConstructor: function(type,constructor) { | ||||||
|             if (nodeConstructors[type]) { |             if (nodeConstructors[type]) { | ||||||
| @@ -214,7 +252,8 @@ var registry = (function() { | |||||||
|                 var result = ""; |                 var result = ""; | ||||||
|                 var script = ""; |                 var script = ""; | ||||||
|                 for (var i=0;i<nodeList.length;i++) { |                 for (var i=0;i<nodeList.length;i++) { | ||||||
|                     var config = nodeConfigs[nodeList[i]]; |                     var id = nodeList[i]; | ||||||
|  |                     var config = moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|                     if (config.enabled && !config.err) { |                     if (config.enabled && !config.err) { | ||||||
|                         result += config.config; |                         result += config.config; | ||||||
|                         script += config.script; |                         script += config.script; | ||||||
| @@ -231,7 +270,7 @@ var registry = (function() { | |||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         getNodeConfig: function(id) { |         getNodeConfig: function(id) { | ||||||
|             var config = nodeConfigs[id]; |             var config = moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|             if (config) { |             if (config) { | ||||||
|                 var result = config.config; |                 var result = config.config; | ||||||
|                 if (config.script) { |                 if (config.script) { | ||||||
| @@ -244,7 +283,15 @@ var registry = (function() { | |||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         getNodeConstructor: function(type) { |         getNodeConstructor: function(type) { | ||||||
|             var config = nodeConfigs[nodeTypeToId[type]]; |             var id = nodeTypeToId[type]; | ||||||
|  |  | ||||||
|  |             var config; | ||||||
|  |             if (typeof id === "undefined") { | ||||||
|  |                 config = undefined; | ||||||
|  |             } else { | ||||||
|  |                 config = moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             if (!config || (config.enabled && !config.err)) { |             if (!config || (config.enabled && !config.err)) { | ||||||
|                 return nodeConstructors[type]; |                 return nodeConstructors[type]; | ||||||
|             } |             } | ||||||
| @@ -253,7 +300,7 @@ var registry = (function() { | |||||||
|  |  | ||||||
|         clear: function() { |         clear: function() { | ||||||
|             nodeConfigCache = null; |             nodeConfigCache = null; | ||||||
|             nodeConfigs = {}; |             moduleConfigs = {}; | ||||||
|             nodeList = []; |             nodeList = []; | ||||||
|             nodeConstructors = {}; |             nodeConstructors = {}; | ||||||
|             nodeTypeToId = {}; |             nodeTypeToId = {}; | ||||||
| @@ -263,21 +310,23 @@ var registry = (function() { | |||||||
|             return nodeTypeToId[type]; |             return nodeTypeToId[type]; | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         getModuleInfo: function(type) { |         getNodeModuleInfo: function(module) { | ||||||
|             return nodeModules[type]; |             return moduleNodes[module]; | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         enableNodeSet: function(id) { |         enableNodeSet: function(typeOrId) { | ||||||
|             if (!settings.available()) { |             if (!settings.available()) { | ||||||
|                 throw new Error("Settings unavailable"); |                 throw new Error("Settings unavailable"); | ||||||
|             } |             } | ||||||
|             var config; |  | ||||||
|             if (nodeTypeToId[id]) { |             var id = typeOrId; | ||||||
|                 config = nodeConfigs[nodeTypeToId[id]]; |             if (nodeTypeToId[typeOrId]) { | ||||||
|             } else { |                 id = nodeTypeToId[typeOrId]; | ||||||
|                 config = nodeConfigs[id]; |  | ||||||
|             } |             } | ||||||
|             if (config) { |  | ||||||
|  |             var config; | ||||||
|  |             try { | ||||||
|  |                 config = moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|                 delete config.err; |                 delete config.err; | ||||||
|                 config.enabled = true; |                 config.enabled = true; | ||||||
|                 if (!config.loaded) { |                 if (!config.loaded) { | ||||||
| @@ -286,28 +335,28 @@ var registry = (function() { | |||||||
|                 } |                 } | ||||||
|                 nodeConfigCache = null; |                 nodeConfigCache = null; | ||||||
|                 saveNodeList(); |                 saveNodeList(); | ||||||
|             } else { |             } catch (err) { | ||||||
|                 throw new Error("Unrecognised id: "+id); |                 throw new Error("Unrecognised id: "+typeOrId); | ||||||
|             } |             } | ||||||
|             return filterNodeInfo(config); |             return filterNodeInfo(config); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         disableNodeSet: function(id) { |         disableNodeSet: function(typeOrId) { | ||||||
|             if (!settings.available()) { |             if (!settings.available()) { | ||||||
|                 throw new Error("Settings unavailable"); |                 throw new Error("Settings unavailable"); | ||||||
|             } |             } | ||||||
|             var config; |             var id = typeOrId; | ||||||
|             if (nodeTypeToId[id]) { |             if (nodeTypeToId[typeOrId]) { | ||||||
|                 config = nodeConfigs[nodeTypeToId[id]]; |                 id = nodeTypeToId[typeOrId]; | ||||||
|             } else { |  | ||||||
|                 config = nodeConfigs[id]; |  | ||||||
|             } |             } | ||||||
|             if (config) { |             var config; | ||||||
|  |             try { | ||||||
|  |                 config = moduleConfigs[getModule(id)].nodes[getNode(id)]; | ||||||
|                 // TODO: persist setting |                 // TODO: persist setting | ||||||
|                 config.enabled = false; |                 config.enabled = false; | ||||||
|                 nodeConfigCache = null; |                 nodeConfigCache = null; | ||||||
|                 saveNodeList(); |                 saveNodeList(); | ||||||
|             } else { |             } catch (err) { | ||||||
|                 throw new Error("Unrecognised id: "+id); |                 throw new Error("Unrecognised id: "+id); | ||||||
|             } |             } | ||||||
|             return filterNodeInfo(config); |             return filterNodeInfo(config); | ||||||
| @@ -315,16 +364,21 @@ var registry = (function() { | |||||||
|  |  | ||||||
|         saveNodeList: saveNodeList, |         saveNodeList: saveNodeList, | ||||||
|  |  | ||||||
|         cleanNodeList: function() { |         cleanModuleList: function() { | ||||||
|             var removed = false; |             var removed = false; | ||||||
|             for (var id in nodeConfigs) { |             for (var mod in moduleConfigs) { | ||||||
|                 if (nodeConfigs.hasOwnProperty(id)) { |                 if (moduleConfigs.hasOwnProperty(mod)) { | ||||||
|                     if (nodeConfigs[id].module && !nodeModules[nodeConfigs[id].module]) { |                     if (moduleConfigs[mod] && !moduleNodes[mod]) { | ||||||
|                         registry.removeNode(id); |                         var nodes = moduleConfigs[mod].nodes; | ||||||
|  |                         for (var node in nodes) { | ||||||
|  |                             if (nodes.hasOwnProperty(node)) { | ||||||
|  |                                 registry.removeNode(mod+"/"+node); | ||||||
|                                 removed = true; |                                 removed = true; | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             if (removed) { |             if (removed) { | ||||||
|                 saveNodeList(); |                 saveNodeList(); | ||||||
|             } |             } | ||||||
| @@ -401,7 +455,7 @@ function scanTreeForNodesModules(moduleName) { | |||||||
|             var files = fs.readdirSync(pm); |             var files = fs.readdirSync(pm); | ||||||
|             for (var i=0;i<files.length;i++) { |             for (var i=0;i<files.length;i++) { | ||||||
|                 var fn = files[i]; |                 var fn = files[i]; | ||||||
|                 if (!registry.getModuleInfo(fn)) { |                 if (!registry.getNodeModuleInfo(fn)) { | ||||||
|                     if (!moduleName || fn == moduleName) { |                     if (!moduleName || fn == moduleName) { | ||||||
|                         var pkgfn = path.join(pm,fn,"package.json"); |                         var pkgfn = path.join(pm,fn,"package.json"); | ||||||
|                         try { |                         try { | ||||||
| @@ -435,7 +489,7 @@ function scanTreeForNodesModules(moduleName) { | |||||||
|  * @param moduleDir the root directory of the package |  * @param moduleDir the root directory of the package | ||||||
|  * @param pkg the module's package.json object |  * @param pkg the module's package.json object | ||||||
|  */ |  */ | ||||||
| function loadNodesFromModule(moduleDir,pkg) { | function loadNodesFromModule(moduleDir,pkg,version) { | ||||||
|     var nodes = pkg['node-red'].nodes||{}; |     var nodes = pkg['node-red'].nodes||{}; | ||||||
|     var results = []; |     var results = []; | ||||||
|     var iconDirs = []; |     var iconDirs = []; | ||||||
| @@ -443,7 +497,7 @@ function loadNodesFromModule(moduleDir,pkg) { | |||||||
|         if (nodes.hasOwnProperty(n)) { |         if (nodes.hasOwnProperty(n)) { | ||||||
|             var file = path.join(moduleDir,nodes[n]); |             var file = path.join(moduleDir,nodes[n]); | ||||||
|             try { |             try { | ||||||
|                 results.push(loadNodeConfig(file,pkg.name,n)); |                 results.push(loadNodeConfig(file,pkg.name,n,version)); | ||||||
|             } catch(err) { |             } catch(err) { | ||||||
|             } |             } | ||||||
|             var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons"); |             var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons"); | ||||||
| @@ -474,20 +528,8 @@ function loadNodesFromModule(moduleDir,pkg) { | |||||||
|  *            types: an array of node type names in this file |  *            types: an array of node type names in this file | ||||||
|  *         } |  *         } | ||||||
|  */ |  */ | ||||||
| function loadNodeConfig(file,module,name) { | function loadNodeConfig(file,module,name,version) { | ||||||
|     var id = crypto.createHash('sha1').update(file).digest("hex"); |     var id = module + "/" + name; | ||||||
|     if (module && name) { |  | ||||||
|         var newid = crypto.createHash('sha1').update(module+":"+name).digest("hex"); |  | ||||||
|         var existingInfo = registry.getNodeInfo(id); |  | ||||||
|         if (existingInfo) { |  | ||||||
|             // For a brief period, id for modules were calculated incorrectly. |  | ||||||
|             // To prevent false-duplicates, this removes the old id entry |  | ||||||
|             registry.removeNode(id); |  | ||||||
|             registry.saveNodeList(); |  | ||||||
|         } |  | ||||||
|         id = newid; |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     var info = registry.getNodeInfo(id); |     var info = registry.getNodeInfo(id); | ||||||
|  |  | ||||||
|     var isEnabled = true; |     var isEnabled = true; | ||||||
| @@ -501,18 +543,14 @@ function loadNodeConfig(file,module,name) { | |||||||
|  |  | ||||||
|     var node = { |     var node = { | ||||||
|         id: id, |         id: id, | ||||||
|  |         module: module, | ||||||
|  |         name: name, | ||||||
|         file: file, |         file: file, | ||||||
|         template: file.replace(/\.js$/,".html"), |         template: file.replace(/\.js$/,".html"), | ||||||
|         enabled: isEnabled, |         enabled: isEnabled, | ||||||
|         loaded:false |         loaded:false | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     if (module) { |  | ||||||
|         node.name = module+":"+name; |  | ||||||
|         node.module = module; |  | ||||||
|     } else { |  | ||||||
|         node.name = path.basename(file); |  | ||||||
|     } |  | ||||||
|     try { |     try { | ||||||
|         var content = fs.readFileSync(node.template,'utf8'); |         var content = fs.readFileSync(node.template,'utf8'); | ||||||
|  |  | ||||||
| @@ -544,7 +582,7 @@ function loadNodeConfig(file,module,name) { | |||||||
|             node.err = err.toString(); |             node.err = err.toString(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     registry.addNodeSet(id,node); |     registry.addNodeSet(id,node,version); | ||||||
|     return node; |     return node; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -576,7 +614,7 @@ function load(defaultNodesDir,disableNodePathScan) { | |||||||
|         var nodes = []; |         var nodes = []; | ||||||
|         nodeFiles.forEach(function(file) { |         nodeFiles.forEach(function(file) { | ||||||
|             try { |             try { | ||||||
|                 nodes.push(loadNodeConfig(file)); |                 nodes.push(loadNodeConfig(file,"node-red",path.basename(file).replace(/^\d+-/,"").replace(/\.js$/,""))); | ||||||
|             } catch(err) { |             } catch(err) { | ||||||
|                 // |                 // | ||||||
|             } |             } | ||||||
| @@ -682,19 +720,19 @@ function addNode(file) { | |||||||
|     } |     } | ||||||
|     var nodes = []; |     var nodes = []; | ||||||
|     try { |     try { | ||||||
|         nodes.push(loadNodeConfig(file)); |         nodes.push(loadNodeConfig(file,"node-red",path.basename(file).replace(/^\d+-/,"").replace(/\.js$/,""))); | ||||||
|     } catch(err) { |     } catch(err) { | ||||||
|         return when.reject(err); |         return when.reject(err); | ||||||
|     } |     } | ||||||
|     return loadNodeList(nodes); |     return loadNodeList(nodes); | ||||||
| } | } | ||||||
|  |  | ||||||
| function addModule(module) { | function addModule(module,version) { | ||||||
|     if (!settings.available()) { |     if (!settings.available()) { | ||||||
|         throw new Error("Settings unavailable"); |         throw new Error("Settings unavailable"); | ||||||
|     } |     } | ||||||
|     var nodes = []; |     var nodes = []; | ||||||
|     if (registry.getModuleInfo(module)) { |     if (registry.getNodeModuleInfo(module)) { | ||||||
|         return when.reject(new Error("Module already loaded")); |         return when.reject(new Error("Module already loaded")); | ||||||
|     } |     } | ||||||
|     var moduleFiles = scanTreeForNodesModules(module); |     var moduleFiles = scanTreeForNodesModules(module); | ||||||
| @@ -704,7 +742,7 @@ function addModule(module) { | |||||||
|         return when.reject(err); |         return when.reject(err); | ||||||
|     } |     } | ||||||
|     moduleFiles.forEach(function(moduleFile) { |     moduleFiles.forEach(function(moduleFile) { | ||||||
|         nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package)); |         nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package,version)); | ||||||
|     }); |     }); | ||||||
|     return loadNodeList(nodes); |     return loadNodeList(nodes); | ||||||
| } | } | ||||||
| @@ -714,14 +752,19 @@ module.exports = { | |||||||
|     load:load, |     load:load, | ||||||
|     clear: registry.clear, |     clear: registry.clear, | ||||||
|     registerType: registry.registerNodeConstructor, |     registerType: registry.registerNodeConstructor, | ||||||
|  |  | ||||||
|     get: registry.getNodeConstructor, |     get: registry.getNodeConstructor, | ||||||
|     getNodeInfo: registry.getNodeInfo, |     getNodeInfo: registry.getNodeInfo, | ||||||
|     getNodeModuleInfo: registry.getModuleInfo, |  | ||||||
|     getPluginInfo: registry.getPluginInfo, |  | ||||||
|     getNodeList: registry.getNodeList, |     getNodeList: registry.getNodeList, | ||||||
|     getPluginList: registry.getPluginList, |  | ||||||
|  |     getNodeModuleInfo: registry.getNodeModuleInfo, | ||||||
|  |  | ||||||
|  |     getModuleInfo: registry.getModuleInfo, | ||||||
|  |     getModuleList: registry.getModuleList, | ||||||
|  |  | ||||||
|     getNodeConfigs: registry.getAllNodeConfigs, |     getNodeConfigs: registry.getAllNodeConfigs, | ||||||
|     getNodeConfig: registry.getNodeConfig, |     getNodeConfig: registry.getNodeConfig, | ||||||
|  |  | ||||||
|     addNode: addNode, |     addNode: addNode, | ||||||
|     removeNode: registry.removeNode, |     removeNode: registry.removeNode, | ||||||
|     enableNode: registry.enableNodeSet, |     enableNode: registry.enableNodeSet, | ||||||
| @@ -729,5 +772,5 @@ module.exports = { | |||||||
|  |  | ||||||
|     addModule: addModule, |     addModule: addModule, | ||||||
|     removeModule: registry.removeModule, |     removeModule: registry.removeModule, | ||||||
|     cleanNodeList: registry.cleanNodeList |     cleanModuleList: registry.cleanModuleList | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -91,7 +91,7 @@ function start() { | |||||||
|                     } |                     } | ||||||
|                     if (!settings.autoInstallModules) { |                     if (!settings.autoInstallModules) { | ||||||
|                         util.log("[red] Removing modules from config"); |                         util.log("[red] Removing modules from config"); | ||||||
|                         redNodes.cleanNodeList(); |                         redNodes.cleanModuleList(); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 defer.resolve(); |                 defer.resolve(); | ||||||
| @@ -162,8 +162,11 @@ function installModule(module) { | |||||||
|                     reject(new Error("Install failed")); |                     reject(new Error("Install failed")); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 util.log("[red] Installed module: "+module); |                 var grandchild = child_process.exec('npm view '+module+' version', function(err, stdin, stdout) { | ||||||
|                 resolve(redNodes.addModule(module).then(reportAddedModules)); |                     var version = stdin.replace(/\s/g, ""); | ||||||
|  |                     util.log("[red] Installed module: "+module+":"+version); | ||||||
|  |                     resolve(redNodes.addModule(module,version).then(reportAddedModules)); | ||||||
|  |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -36,8 +36,10 @@ describe("nodes api", function() { | |||||||
|         app.use(express.json()); |         app.use(express.json()); | ||||||
|         app.get("/nodes",nodes.getAll); |         app.get("/nodes",nodes.getAll); | ||||||
|         app.post("/nodes",nodes.post); |         app.post("/nodes",nodes.post); | ||||||
|         app.get("/nodes/:id",nodes.get); |         app.get("/nodes/:mod",nodes.getModule); | ||||||
|         app.put("/nodes/:id",nodes.put); |         app.get("/nodes/:mod/:set",nodes.getSet); | ||||||
|  |         app.put("/nodes/:mod",nodes.putModule); | ||||||
|  |         app.put("/nodes/:mod/:set",nodes.putSet); | ||||||
|         app.delete("/nodes/:id",nodes.delete); |         app.delete("/nodes/:id",nodes.delete); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| @@ -78,12 +80,45 @@ describe("nodes api", function() { | |||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('returns an individual node info', function(done) { |         it('returns node module info', function(done) { | ||||||
|             var getNodeInfo = sinon.stub(redNodes,'getNodeInfo', function(id) { |             var getNodeInfo = sinon.stub(redNodes,'getModuleInfo', function(id) { | ||||||
|                 return {"123":{id:"123"}}[id]; |                 return {"node-red":{name:"node-red"}}[id]; | ||||||
|             }); |             }); | ||||||
|             request(app) |             request(app) | ||||||
|                 .get('/nodes/123') |                 .get('/nodes/node-red') | ||||||
|  |                 .expect(200) | ||||||
|  |                 .end(function(err,res) { | ||||||
|  |                     getNodeInfo.restore(); | ||||||
|  |                     if (err) { | ||||||
|  |                         throw err; | ||||||
|  |                     } | ||||||
|  |                     res.body.should.have.property("name","node-red"); | ||||||
|  |                     done(); | ||||||
|  |                 }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('returns 404 for unknown module', function(done) { | ||||||
|  |             var getNodeInfo = sinon.stub(redNodes,'getModuleInfo', function(id) { | ||||||
|  |                 return {"node-red":{name:"node-red"}}[id]; | ||||||
|  |             }); | ||||||
|  |             request(app) | ||||||
|  |                 .get('/nodes/node-blue') | ||||||
|  |                 .expect(404) | ||||||
|  |                 .end(function(err,res) { | ||||||
|  |                     getNodeInfo.restore(); | ||||||
|  |                     if (err) { | ||||||
|  |                         throw err; | ||||||
|  |                     } | ||||||
|  |                     done(); | ||||||
|  |                 }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('returns individual node info', function(done) { | ||||||
|  |             var getNodeInfo = sinon.stub(redNodes,'getNodeInfo', function(id) { | ||||||
|  |                 return {"node-red/123":{id:"node-red/123"}}[id]; | ||||||
|  |             }); | ||||||
|  |             request(app) | ||||||
|  |                 .get('/nodes/node-red/123') | ||||||
|                 .set('Accept', 'application/json') |                 .set('Accept', 'application/json') | ||||||
|                 .expect(200) |                 .expect(200) | ||||||
|                 .end(function(err,res) { |                 .end(function(err,res) { | ||||||
| @@ -91,17 +126,17 @@ describe("nodes api", function() { | |||||||
|                     if (err) { |                     if (err) { | ||||||
|                         throw err; |                         throw err; | ||||||
|                     } |                     } | ||||||
|                     res.body.should.have.property("id","123"); |                     res.body.should.have.property("id","node-red/123"); | ||||||
|                     done(); |                     done(); | ||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('returns an individual node configs', function(done) { |         it('returns individual node configs', function(done) { | ||||||
|             var getNodeConfig = sinon.stub(redNodes,'getNodeConfig', function(id) { |             var getNodeConfig = sinon.stub(redNodes,'getNodeConfig', function(id) { | ||||||
|                 return {"123":"<script></script>"}[id]; |                 return {"node-red/123":"<script></script>"}[id]; | ||||||
|             }); |             }); | ||||||
|             request(app) |             request(app) | ||||||
|                 .get('/nodes/123') |                 .get('/nodes/node-red/123') | ||||||
|                 .set('Accept', 'text/html') |                 .set('Accept', 'text/html') | ||||||
|                 .expect(200) |                 .expect(200) | ||||||
|                 .expect("<script></script>") |                 .expect("<script></script>") | ||||||
| @@ -116,10 +151,10 @@ describe("nodes api", function() { | |||||||
|  |  | ||||||
|         it('returns 404 for unknown node', function(done) { |         it('returns 404 for unknown node', function(done) { | ||||||
|             var getNodeInfo = sinon.stub(redNodes,'getNodeInfo', function(id) { |             var getNodeInfo = sinon.stub(redNodes,'getNodeInfo', function(id) { | ||||||
|                 return {"123":{id:"123"}}[id]; |                 return {"node-red/123":{id:"node-red/123"}}[id]; | ||||||
|             }); |             }); | ||||||
|             request(app) |             request(app) | ||||||
|                 .get('/nodes/456') |                 .get('/nodes/node-red/456') | ||||||
|                 .set('Accept', 'application/json') |                 .set('Accept', 'application/json') | ||||||
|                 .expect(404) |                 .expect(404) | ||||||
|                 .end(function(err,res) { |                 .end(function(err,res) { | ||||||
| @@ -168,13 +203,21 @@ describe("nodes api", function() { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         describe('by module', function() { |         describe('by module', function() { | ||||||
|             it('installs the module and returns node info', function(done) { |             it('installs the module and returns module info', function(done) { | ||||||
|                 var settingsAvailable = sinon.stub(settings,'available', function() { |                 var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|                     return true; |                     return true; | ||||||
|                 }); |                 }); | ||||||
|                 var getNodeModuleInfo = sinon.stub(redNodes,'getNodeModuleInfo',function(id) { |                 var getNodeModuleInfo = sinon.stub(redNodes,'getNodeModuleInfo',function(id) { | ||||||
|                     return null; |                     return null; | ||||||
|                 }); |                 }); | ||||||
|  |                 var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(module) { | ||||||
|  |                     if (module === "foo") { | ||||||
|  |                         return { | ||||||
|  |                             name:"foo", | ||||||
|  |                             nodes:[{id:123}] | ||||||
|  |                         }; | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|                 var installModule = sinon.stub(server,'installModule', function() { |                 var installModule = sinon.stub(server,'installModule', function() { | ||||||
|                     return when.resolve({id:"123"}); |                     return when.resolve({id:"123"}); | ||||||
|                 }); |                 }); | ||||||
| @@ -186,11 +229,14 @@ describe("nodes api", function() { | |||||||
|                     .end(function(err,res) { |                     .end(function(err,res) { | ||||||
|                         settingsAvailable.restore(); |                         settingsAvailable.restore(); | ||||||
|                         getNodeModuleInfo.restore(); |                         getNodeModuleInfo.restore(); | ||||||
|  |                         getModuleInfo.restore(); | ||||||
|                         installModule.restore(); |                         installModule.restore(); | ||||||
|                         if (err) { |                         if (err) { | ||||||
|                             throw err; |                             throw err; | ||||||
|                         } |                         } | ||||||
|                         res.body.should.have.property("id","123"); |                         res.body.should.have.property("name","foo"); | ||||||
|  |                         res.body.should.have.property("nodes"); | ||||||
|  |                         res.body.nodes[0].should.have.property("id","123"); | ||||||
|                         done(); |                         done(); | ||||||
|                     }); |                     }); | ||||||
|             }); |             }); | ||||||
| @@ -294,7 +340,7 @@ describe("nodes api", function() { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         describe('by module', function() { |         describe('by module', function() { | ||||||
|             it('uninstalls the module and returns node info', function(done) { |             it('uninstalls the module', function(done) { | ||||||
|                 var settingsAvailable = sinon.stub(settings,'available', function() { |                 var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|                     return true; |                     return true; | ||||||
|                 }); |                 }); | ||||||
| @@ -310,7 +356,7 @@ describe("nodes api", function() { | |||||||
|  |  | ||||||
|                 request(app) |                 request(app) | ||||||
|                     .del('/nodes/foo') |                     .del('/nodes/foo') | ||||||
|                     .expect(200) |                     .expect(204) | ||||||
|                     .end(function(err,res) { |                     .end(function(err,res) { | ||||||
|                         settingsAvailable.restore(); |                         settingsAvailable.restore(); | ||||||
|                         getNodeInfo.restore(); |                         getNodeInfo.restore(); | ||||||
| @@ -319,7 +365,6 @@ describe("nodes api", function() { | |||||||
|                         if (err) { |                         if (err) { | ||||||
|                             throw err; |                             throw err; | ||||||
|                         } |                         } | ||||||
|                         res.body.should.have.property("id","123"); |  | ||||||
|                         done(); |                         done(); | ||||||
|                     }); |                     }); | ||||||
|             }); |             }); | ||||||
| @@ -399,7 +444,27 @@ describe("nodes api", function() { | |||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('returns 400 for invalid payload', function(done) { |         it('returns 400 for invalid node payload', function(done) { | ||||||
|  |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             request(app) | ||||||
|  |                 .put('/nodes/node-red/foo') | ||||||
|  |                 .send({}) | ||||||
|  |                 .expect(400) | ||||||
|  |                 .end(function(err,res) { | ||||||
|  |                     settingsAvailable.restore(); | ||||||
|  |                     if (err) { | ||||||
|  |                         throw err; | ||||||
|  |                     } | ||||||
|  |                     res.text.should.equal("Invalid request"); | ||||||
|  |  | ||||||
|  |                     done(); | ||||||
|  |                 }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('returns 400 for invalid module payload', function(done) { | ||||||
|             var settingsAvailable = sinon.stub(settings,'available', function() { |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
| @@ -418,6 +483,7 @@ describe("nodes api", function() { | |||||||
|                     done(); |                     done(); | ||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('returns 404 for unknown node', function(done) { |         it('returns 404 for unknown node', function(done) { | ||||||
|             var settingsAvailable = sinon.stub(settings,'available', function() { |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|                 return true; |                 return true; | ||||||
| @@ -427,7 +493,7 @@ describe("nodes api", function() { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             request(app) |             request(app) | ||||||
|                 .put('/nodes/foo') |                 .put('/nodes/node-red/foo') | ||||||
|                 .send({enabled:false}) |                 .send({enabled:false}) | ||||||
|                 .expect(404) |                 .expect(404) | ||||||
|                 .end(function(err,res) { |                 .end(function(err,res) { | ||||||
| @@ -440,6 +506,28 @@ describe("nodes api", function() { | |||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         it('returns 404 for unknown module', function(done) { | ||||||
|  |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |             var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(id) { | ||||||
|  |                 return null; | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             request(app) | ||||||
|  |                 .put('/nodes/node-blue') | ||||||
|  |                 .send({enabled:false}) | ||||||
|  |                 .expect(404) | ||||||
|  |                 .end(function(err,res) { | ||||||
|  |                     settingsAvailable.restore(); | ||||||
|  |                     getModuleInfo.restore(); | ||||||
|  |                     if (err) { | ||||||
|  |                         throw err; | ||||||
|  |                     } | ||||||
|  |                     done(); | ||||||
|  |                 }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         it('enables disabled node', function(done) { |         it('enables disabled node', function(done) { | ||||||
|             var settingsAvailable = sinon.stub(settings,'available', function() { |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|                 return true; |                 return true; | ||||||
| @@ -452,7 +540,7 @@ describe("nodes api", function() { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             request(app) |             request(app) | ||||||
|                 .put('/nodes/foo') |                 .put('/nodes/node-red/foo') | ||||||
|                 .send({enabled:true}) |                 .send({enabled:true}) | ||||||
|                 .expect(200) |                 .expect(200) | ||||||
|                 .end(function(err,res) { |                 .end(function(err,res) { | ||||||
| @@ -468,6 +556,7 @@ describe("nodes api", function() { | |||||||
|                     done(); |                     done(); | ||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         it('disables enabled node', function(done) { |         it('disables enabled node', function(done) { | ||||||
|             var settingsAvailable = sinon.stub(settings,'available', function() { |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|                 return true; |                 return true; | ||||||
| @@ -480,7 +569,7 @@ describe("nodes api", function() { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             request(app) |             request(app) | ||||||
|                 .put('/nodes/foo') |                 .put('/nodes/node-red/foo') | ||||||
|                 .send({enabled:false}) |                 .send({enabled:false}) | ||||||
|                 .expect(200) |                 .expect(200) | ||||||
|                 .end(function(err,res) { |                 .end(function(err,res) { | ||||||
| @@ -496,6 +585,7 @@ describe("nodes api", function() { | |||||||
|                     done(); |                     done(); | ||||||
|                 }); |                 }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         describe('no-ops if already in the right state', function() { |         describe('no-ops if already in the right state', function() { | ||||||
|             function run(state,done) { |             function run(state,done) { | ||||||
|                 var settingsAvailable = sinon.stub(settings,'available', function() { |                 var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
| @@ -513,7 +603,7 @@ describe("nodes api", function() { | |||||||
|                 }); |                 }); | ||||||
|  |  | ||||||
|                 request(app) |                 request(app) | ||||||
|                     .put('/nodes/foo') |                     .put('/nodes/node-red/foo') | ||||||
|                     .send({enabled:state}) |                     .send({enabled:state}) | ||||||
|                     .expect(200) |                     .expect(200) | ||||||
|                     .end(function(err,res) { |                     .end(function(err,res) { | ||||||
| @@ -541,6 +631,7 @@ describe("nodes api", function() { | |||||||
|                 run(false,done); |                 run(false,done); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         describe('does not no-op if err on node', function() { |         describe('does not no-op if err on node', function() { | ||||||
|             function run(state,done) { |             function run(state,done) { | ||||||
|                 var settingsAvailable = sinon.stub(settings,'available', function() { |                 var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
| @@ -558,7 +649,7 @@ describe("nodes api", function() { | |||||||
|                 }); |                 }); | ||||||
|  |  | ||||||
|                 request(app) |                 request(app) | ||||||
|                     .put('/nodes/foo') |                     .put('/nodes/node-red/foo') | ||||||
|                     .send({enabled:state}) |                     .send({enabled:state}) | ||||||
|                     .expect(200) |                     .expect(200) | ||||||
|                     .end(function(err,res) { |                     .end(function(err,res) { | ||||||
| @@ -586,6 +677,186 @@ describe("nodes api", function() { | |||||||
|                 run(false,done); |                 run(false,done); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         it('enables disabled module', function(done) { | ||||||
|  |             var n1 = {id:"123",enabled:false,types:['a']}; | ||||||
|  |             var n2 = {id:"456",enabled:false,types:['b']}; | ||||||
|  |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |             var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(name) { | ||||||
|  |                 return {name:"node-red", nodes:[n1, n2]}; | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             var enableNode = sinon.stub(redNodes,'enableNode'); | ||||||
|  |             enableNode.onFirstCall().returns((function() { | ||||||
|  |                 n1.enabled = true; | ||||||
|  |                 return n1; | ||||||
|  |             })()); | ||||||
|  |             enableNode.onSecondCall().returns((function() { | ||||||
|  |                 n2.enabled = true; | ||||||
|  |                 return n2; | ||||||
|  |             })()); | ||||||
|  |             enableNode.returns(null); | ||||||
|  |  | ||||||
|  |             request(app) | ||||||
|  |                 .put('/nodes/node-red') | ||||||
|  |                 .send({enabled:true}) | ||||||
|  |                 .expect(200) | ||||||
|  |                 .end(function(err,res) { | ||||||
|  |                     settingsAvailable.restore(); | ||||||
|  |                     getModuleInfo.restore(); | ||||||
|  |                     enableNode.restore(); | ||||||
|  |                     if (err) { | ||||||
|  |                         throw err; | ||||||
|  |                     } | ||||||
|  |                     res.body.should.have.property("name","node-red"); | ||||||
|  |                     res.body.should.have.property("nodes"); | ||||||
|  |                     res.body.nodes[0].should.have.property("enabled",true); | ||||||
|  |                     res.body.nodes[1].should.have.property("enabled",true); | ||||||
|  |  | ||||||
|  |                     done(); | ||||||
|  |                 }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         it('disables enabled module', function(done) { | ||||||
|  |             var n1 = {id:"123",enabled:true,types:['a']}; | ||||||
|  |             var n2 = {id:"456",enabled:true,types:['b']}; | ||||||
|  |             var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |             var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(name) { | ||||||
|  |                 return {name:"node-red", nodes:[n1, n2]}; | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             var disableNode = sinon.stub(redNodes,'disableNode'); | ||||||
|  |             disableNode.onFirstCall().returns((function() { | ||||||
|  |                 n1.enabled = false; | ||||||
|  |                 return n1; | ||||||
|  |             })()); | ||||||
|  |             disableNode.onSecondCall().returns((function() { | ||||||
|  |                 n2.enabled = false; | ||||||
|  |                 return n2; | ||||||
|  |             })()); | ||||||
|  |             disableNode.returns(null); | ||||||
|  |  | ||||||
|  |             request(app) | ||||||
|  |                 .put('/nodes/node-red') | ||||||
|  |                 .send({enabled:false}) | ||||||
|  |                 .expect(200) | ||||||
|  |                 .end(function(err,res) { | ||||||
|  |                     settingsAvailable.restore(); | ||||||
|  |                     getModuleInfo.restore(); | ||||||
|  |                     disableNode.restore(); | ||||||
|  |                     if (err) { | ||||||
|  |                         throw err; | ||||||
|  |                     } | ||||||
|  |                     res.body.should.have.property("name","node-red"); | ||||||
|  |                     res.body.should.have.property("nodes"); | ||||||
|  |                     res.body.nodes[0].should.have.property("enabled",false); | ||||||
|  |                     res.body.nodes[1].should.have.property("enabled",false); | ||||||
|  |  | ||||||
|  |                     done(); | ||||||
|  |                 }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         describe('no-ops if a node in module already in the right state', function() { | ||||||
|  |             function run(state,done) { | ||||||
|  |                 var node = {id:"123",enabled:state,types:['a']}; | ||||||
|  |                 var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |                 var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(id) { | ||||||
|  |                     return {name:"node-red", nodes:[node]}; | ||||||
|  |                 }); | ||||||
|  |                 var enableNode = sinon.stub(redNodes,'enableNode',function(id) { | ||||||
|  |                     node.enabled = true; | ||||||
|  |                     return node; | ||||||
|  |                 }); | ||||||
|  |                 var disableNode = sinon.stub(redNodes,'disableNode',function(id) { | ||||||
|  |                     node.enabled = false; | ||||||
|  |                     return node; | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |                 request(app) | ||||||
|  |                     .put('/nodes/node-red') | ||||||
|  |                     .send({enabled:state}) | ||||||
|  |                     .expect(200) | ||||||
|  |                     .end(function(err,res) { | ||||||
|  |                         settingsAvailable.restore(); | ||||||
|  |                         getModuleInfo.restore(); | ||||||
|  |                         var enableNodeCalled = enableNode.called; | ||||||
|  |                         var disableNodeCalled = disableNode.called; | ||||||
|  |                         enableNode.restore(); | ||||||
|  |                         disableNode.restore(); | ||||||
|  |                         if (err) { | ||||||
|  |                             throw err; | ||||||
|  |                         } | ||||||
|  |                         enableNodeCalled.should.be.false; | ||||||
|  |                         disableNodeCalled.should.be.false; | ||||||
|  |                         res.body.should.have.property("name","node-red"); | ||||||
|  |                         res.body.should.have.property("nodes"); | ||||||
|  |                         res.body.nodes[0].should.have.property("enabled",state); | ||||||
|  |  | ||||||
|  |                         done(); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |             it('already enabled', function(done) { | ||||||
|  |                 run(true,done); | ||||||
|  |             }); | ||||||
|  |             it('already disabled', function(done) { | ||||||
|  |                 run(false,done); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         describe('does not no-op if err on a node in module', function() { | ||||||
|  |             function run(state,done) { | ||||||
|  |                 var node = {id:"123",enabled:state,types:['a'],err:"foo"}; | ||||||
|  |                 var settingsAvailable = sinon.stub(settings,'available', function() { | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |                 var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(id) { | ||||||
|  |                     return {name:"node-red", nodes:[node]}; | ||||||
|  |                 }); | ||||||
|  |                 var enableNode = sinon.stub(redNodes,'enableNode',function(id) { | ||||||
|  |                     node.enabled = true; | ||||||
|  |                     return node; | ||||||
|  |                 }); | ||||||
|  |                 var disableNode = sinon.stub(redNodes,'disableNode',function(id) { | ||||||
|  |                     node.enabled = false; | ||||||
|  |                     return node; | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |                 request(app) | ||||||
|  |                     .put('/nodes/node-red') | ||||||
|  |                     .send({enabled:state}) | ||||||
|  |                     .expect(200) | ||||||
|  |                     .end(function(err,res) { | ||||||
|  |                         settingsAvailable.restore(); | ||||||
|  |                         getModuleInfo.restore(); | ||||||
|  |                         var enableNodeCalled = enableNode.called; | ||||||
|  |                         var disableNodeCalled = disableNode.called; | ||||||
|  |                         enableNode.restore(); | ||||||
|  |                         disableNode.restore(); | ||||||
|  |                         if (err) { | ||||||
|  |                             throw err; | ||||||
|  |                         } | ||||||
|  |                         enableNodeCalled.should.be.equal(state); | ||||||
|  |                         disableNodeCalled.should.be.equal(!state); | ||||||
|  |                         res.body.should.have.property("name","node-red"); | ||||||
|  |                         res.body.should.have.property("nodes"); | ||||||
|  |                         res.body.nodes[0].should.have.property("enabled",state); | ||||||
|  |  | ||||||
|  |                         done(); | ||||||
|  |                     }); | ||||||
|  |             } | ||||||
|  |             it('already enabled', function(done) { | ||||||
|  |                 run(true,done); | ||||||
|  |             }); | ||||||
|  |             it('already disabled', function(done) { | ||||||
|  |                 run(false,done); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,77 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 request = require('supertest'); |  | ||||||
| var express = require('express'); |  | ||||||
| var sinon = require('sinon'); |  | ||||||
| var when = require('when'); |  | ||||||
|  |  | ||||||
| var app = express(); |  | ||||||
| var redNodes = require("../../../red/nodes"); |  | ||||||
| var server = require("../../../red/server"); |  | ||||||
| var settings = require("../../../red/settings"); |  | ||||||
|  |  | ||||||
| var plugins = require("../../../red/api/plugins"); |  | ||||||
|  |  | ||||||
| describe("plugins api", function() { |  | ||||||
|  |  | ||||||
|     var app; |  | ||||||
|  |  | ||||||
|     before(function() { |  | ||||||
|         app = express(); |  | ||||||
|         app.use(express.json()); |  | ||||||
|         app.get("/plugins",plugins.getAll); |  | ||||||
|         app.get("/plugins/:id",plugins.get); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     describe('get plugins', function() { |  | ||||||
|         it('returns plugins list', function(done) { |  | ||||||
|             var getPluginList = sinon.stub(redNodes,'getPluginList', function() { |  | ||||||
|                 return [1,2,3]; |  | ||||||
|             }); |  | ||||||
|             request(app) |  | ||||||
|                 .get('/plugins') |  | ||||||
|                 .expect(200) |  | ||||||
|                 .end(function(err,res) { |  | ||||||
|                     getPluginList.restore(); |  | ||||||
|                     if (err) { |  | ||||||
|                         throw err; |  | ||||||
|                     } |  | ||||||
|                     res.body.should.be.an.Array.and.have.lengthOf(3); |  | ||||||
|                     done(); |  | ||||||
|                 }); |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         it('returns an individual plugin info', function(done) { |  | ||||||
|             var getPluginInfo = sinon.stub(redNodes,'getPluginInfo', function(id) { |  | ||||||
|                 return {"name":"123", "nodes":[1,2,3]}; |  | ||||||
|             }); |  | ||||||
|             request(app) |  | ||||||
|                 .get('/plugins/123') |  | ||||||
|                 .expect(200) |  | ||||||
|                 .end(function(err,res) { |  | ||||||
|                     getPluginInfo.restore(); |  | ||||||
|                     if (err) { |  | ||||||
|                         throw err; |  | ||||||
|                     } |  | ||||||
|                     res.body.should.have.property("name","123"); |  | ||||||
|                     res.body.should.have.property("nodes",[1,2,3]); |  | ||||||
|                     done(); |  | ||||||
|                 }); |  | ||||||
|         }); |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 fs = require("fs"); |  | ||||||
|  |  | ||||||
| var config = require("../../../../red/cli/lib/config"); |  | ||||||
|  |  | ||||||
| describe("cli config", function() { |  | ||||||
|     afterEach(function() { |  | ||||||
|         config.unload(); |  | ||||||
|     }); |  | ||||||
|     it('loads preferences when target referenced', sinon.test(function() { |  | ||||||
|         this.stub(fs,"readFileSync",function() { |  | ||||||
|             return '{"target":"http://example.com:1880"}' |  | ||||||
|         }); |  | ||||||
|         config.target.should.eql("http://example.com:1880"); |  | ||||||
|     })); |  | ||||||
|     it('provide default value for target', sinon.test(function() { |  | ||||||
|         this.stub(fs,"readFileSync",function() { |  | ||||||
|             return '{}' |  | ||||||
|         }); |  | ||||||
|         config.target.should.eql("http://localhost:1880"); |  | ||||||
|     })); |  | ||||||
|     it('saves preferences when target set', sinon.test(function() { |  | ||||||
|         this.stub(fs,"readFileSync",function() { |  | ||||||
|             return '{"target":"http://another.example.com:1880"}' |  | ||||||
|         }); |  | ||||||
|         this.stub(fs,"writeFileSync",function() {}); |  | ||||||
|          |  | ||||||
|         config.target.should.eql("http://another.example.com:1880"); |  | ||||||
|         config.target = "http://final.example.com:1880"; |  | ||||||
|          |  | ||||||
|         fs.readFileSync.calledOnce.should.be.true; |  | ||||||
|         fs.writeFileSync.calledOnce.should.be.true; |  | ||||||
|          |  | ||||||
|     })); |  | ||||||
|          |  | ||||||
| }); |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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 fs = require("fs"); |  | ||||||
| var request = require("request"); |  | ||||||
|  |  | ||||||
| var apiRequest = require("../../../../red/cli/lib/request"); |  | ||||||
| var config = require("../../../../red/cli/lib/config"); |  | ||||||
|  |  | ||||||
| describe("cli request", function() { |  | ||||||
|     var sandbox = sinon.sandbox.create(); |  | ||||||
|     before(function() { |  | ||||||
|         sandbox.stub(fs,"readFileSync",function() { |  | ||||||
|             return '{"target":"http://example.com:1880"}' |  | ||||||
|         }); |  | ||||||
|     }); |  | ||||||
|     after(function() { |  | ||||||
|         sandbox.restore(); |  | ||||||
|     }); |  | ||||||
|                  |  | ||||||
|     it('returns the json response to a get', sinon.test(function(done) { |  | ||||||
|         this.stub(request, 'get').yields(null, {statusCode:200}, JSON.stringify({a: "b"})); |  | ||||||
|              |  | ||||||
|         apiRequest("/foo",{}).then(function(res) { |  | ||||||
|             res.should.eql({a:"b"}); |  | ||||||
|             done(); |  | ||||||
|         }).otherwise(function(err) { |  | ||||||
|             done(err); |  | ||||||
|         }); |  | ||||||
|     })); |  | ||||||
| }); |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright 2014 IBM Corp. |  | ||||||
|  * |  | ||||||
|  * 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. |  | ||||||
|  **/ |  | ||||||
| @@ -135,7 +135,7 @@ describe("red/nodes/index", function() { | |||||||
|  |  | ||||||
|    }); |    }); | ||||||
|  |  | ||||||
|    describe('allows nodes to be added/remove/enabled/disabled from the registry', function() { |    describe('allows nodes to be added/removed/enabled/disabled from the registry', function() { | ||||||
|        var registry = require("../../../red/nodes/registry"); |        var registry = require("../../../red/nodes/registry"); | ||||||
|        var randomNodeInfo = {id:"5678",types:["random"]}; |        var randomNodeInfo = {id:"5678",types:["random"]}; | ||||||
|  |  | ||||||
| @@ -248,8 +248,73 @@ describe("red/nodes/index", function() { | |||||||
|                 done(err); |                 done(err); | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |    describe('allows modules to be removed from the registry', function() { | ||||||
|  |        var registry = require("../../../red/nodes/registry"); | ||||||
|  |        var randomNodeInfo = {id:"5678",types:["random"]}; | ||||||
|  |        var randomModuleInfo = { | ||||||
|  |           name:"random", | ||||||
|  |           nodes: [randomNodeInfo] | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |        before(function() { | ||||||
|  |            sinon.stub(registry,"getNodeInfo",function(id) { | ||||||
|  |                if (id == "node-red/foo") { | ||||||
|  |                    return {id:"1234",types:["test"]}; | ||||||
|  |                } else if (id == "doesnotexist") { | ||||||
|  |                    return null; | ||||||
|  |                } else { | ||||||
|  |                    return randomNodeInfo; | ||||||
|  |                } | ||||||
|  |            }); | ||||||
|  |            sinon.stub(registry,"getNodeModuleInfo",function(module) { | ||||||
|  |                if (module == "node-red") { | ||||||
|  |                   return ["foo"]; | ||||||
|  |                } else if (module == "doesnotexist") { | ||||||
|  |                    return null; | ||||||
|  |                } else { | ||||||
|  |                   return randomModuleInfo.nodes; | ||||||
|  |                } | ||||||
|  |            }); | ||||||
|  |            sinon.stub(registry,"removeModule",function(id) { | ||||||
|  |                return randomModuleInfo; | ||||||
|  |            }); | ||||||
|  |        }); | ||||||
|  |        after(function() { | ||||||
|  |            registry.getNodeInfo.restore(); | ||||||
|  |            registry.getNodeModuleInfo.restore(); | ||||||
|  |            registry.removeModule.restore(); | ||||||
|  |        }); | ||||||
|  |  | ||||||
|  |        it(': prevents removing a module that is in use',function(done) { | ||||||
|  |             index.init(settings, storage); | ||||||
|  |             index.registerType('test', TestNode); | ||||||
|  |             index.loadFlows().then(function() { | ||||||
|  |                 /*jshint immed: false */ | ||||||
|  |                 (function() { | ||||||
|  |                     index.removeModule("node-red"); | ||||||
|  |                 }).should.throw(); | ||||||
|  |  | ||||||
|  |                 done(); | ||||||
|  |             }).otherwise(function(err) { | ||||||
|  |                 done(err); | ||||||
|  |             }); | ||||||
|  |        }); | ||||||
|  |  | ||||||
|  |        it(': prevents removing a module that is unknown',function(done) { | ||||||
|  |             index.init(settings, storage); | ||||||
|  |             index.registerType('test', TestNode); | ||||||
|  |             index.loadFlows().then(function() { | ||||||
|  |                 /*jshint immed: false */ | ||||||
|  |                 (function() { | ||||||
|  |                     index.removeModule("doesnotexist"); | ||||||
|  |                 }).should.throw(); | ||||||
|  |  | ||||||
|  |                 done(); | ||||||
|  |             }).otherwise(function(err) { | ||||||
|  |                 done(err); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -33,10 +33,10 @@ describe('NodeRegistry', function() { | |||||||
|     var resourcesDir = __dirname+ path.sep + "resources" + path.sep; |     var resourcesDir = __dirname+ path.sep + "resources" + path.sep; | ||||||
|  |  | ||||||
|     function stubSettings(s,available) { |     function stubSettings(s,available) { | ||||||
|         s.available =  function() {return available;} |         s.available =  function() {return available;}; | ||||||
|         s.set = function(s,v) { return when.resolve()}, |         s.set = function(s,v) { return when.resolve();}; | ||||||
|         s.get = function(s) { return null;} |         s.get = function(s) { return null;}; | ||||||
|         return s |         return s; | ||||||
|     } |     } | ||||||
|     var settings = stubSettings({},false); |     var settings = stubSettings({},false); | ||||||
|     var settingsWithStorage = stubSettings({},true); |     var settingsWithStorage = stubSettings({},true); | ||||||
| @@ -56,8 +56,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "TestNode1",true).then(function() { |         typeRegistry.load(resourcesDir + "TestNode1",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|             list[0].should.have.property("name","TestNode1.js"); |             list[0].should.have.property("name","TestNode1"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-1"]); |             list[0].should.have.property("types",["test-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
| @@ -78,8 +79,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "TestNode2",true).then(function() { |         typeRegistry.load(resourcesDir + "TestNode2",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode2"); | ||||||
|             list[0].should.have.property("name","TestNode2.js"); |             list[0].should.have.property("name","TestNode2"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-2"]); |             list[0].should.have.property("types",["test-node-2"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
| @@ -98,8 +100,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "TestNode3",true).then(function() { |         typeRegistry.load(resourcesDir + "TestNode3",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode3"); | ||||||
|             list[0].should.have.property("name","TestNode3.js"); |             list[0].should.have.property("name","TestNode3"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-3"]); |             list[0].should.have.property("types",["test-node-3"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.have.property("err","fail"); |             list[0].should.have.property("err","fail"); | ||||||
| @@ -119,8 +122,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "MultipleNodes1",true).then(function() { |         typeRegistry.load(resourcesDir + "MultipleNodes1",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/MultipleNodes1"); | ||||||
|             list[0].should.have.property("name","MultipleNodes1.js"); |             list[0].should.have.property("name","MultipleNodes1"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-multiple-1a","test-node-multiple-1b"]); |             list[0].should.have.property("types",["test-node-multiple-1a","test-node-multiple-1b"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
| @@ -142,8 +146,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "NestedDirectoryNode",true).then(function() { |         typeRegistry.load(resourcesDir + "NestedDirectoryNode",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/NestedNode"); | ||||||
|             list[0].should.have.property("name","NestedNode.js"); |             list[0].should.have.property("name","NestedNode"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["nested-node-1"]); |             list[0].should.have.property("types",["nested-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
| @@ -159,7 +164,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "NestedDirectoryNode",true).then(function() { |         typeRegistry.load(resourcesDir + "NestedDirectoryNode",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("name","NestedNode.js"); |             list[0].should.have.property("id","node-red/NestedNode"); | ||||||
|  |             list[0].should.have.property("name","NestedNode"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["nested-node-1"]); |             list[0].should.have.property("types",["nested-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
| @@ -189,26 +196,13 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load("wontexist",true).then(function() { |         typeRegistry.load("wontexist",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|  |  | ||||||
|             list.should.be.an.Array.and.have.lengthOf(2); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|             list[0].should.have.property("name","TestNode1.js"); |             list[0].should.have.property("name","TestNode1"); | ||||||
|             list[0].should.have.property("types",["test-node-1"]); |             list[0].should.have.property("types",["test-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
|  |  | ||||||
|             list[1].should.have.property("id"); |  | ||||||
|             list[1].id.should.not.equal(list[0].id); |  | ||||||
|  |  | ||||||
|             list[1].should.have.property("name","TestNode1.js"); |  | ||||||
|             list[1].should.have.property("types",["test-node-1"]); |  | ||||||
|             list[1].should.have.property("enabled",true); |  | ||||||
|             list[1].should.have.property("err"); |  | ||||||
|             /already registered/.test(list[1].err).should.be.true; |  | ||||||
|  |  | ||||||
|             var nodeConstructor = typeRegistry.get("test-node-1"); |  | ||||||
|             // Verify the duplicate node hasn't replaced the original one |  | ||||||
|             nodeConstructor.name.should.be.equal("TestNode"); |  | ||||||
|  |  | ||||||
|             done(); |             done(); | ||||||
|         }).catch(function(e) { |         }).catch(function(e) { | ||||||
|             done(e); |             done(e); | ||||||
| @@ -297,24 +291,28 @@ describe('NodeRegistry', function() { | |||||||
|             available: function() { return true; }, |             available: function() { return true; }, | ||||||
|             set: function(s,v) { return when.resolve(); }, |             set: function(s,v) { return when.resolve(); }, | ||||||
|             get: function(s) { return null; } |             get: function(s) { return null; } | ||||||
|         } |         }; | ||||||
|         var settingsSave = sinon.spy(settings,"set"); |         var settingsSave = sinon.spy(settings,"set"); | ||||||
|         typeRegistry.init(settings); |         typeRegistry.init(settings); | ||||||
|         typeRegistry.load("wontexist",true).then(function() { |         typeRegistry.load("wontexist",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var nodeList = typeRegistry.getNodeList(); | ||||||
|             list.should.be.Array.and.have.length(3); |             var moduleList = typeRegistry.getModuleList(); | ||||||
|  |             nodeList.should.be.Array.and.have.length(3); | ||||||
|  |             moduleList.should.be.Array.and.have.length(1); | ||||||
|  |  | ||||||
|             settingsSave.callCount.should.equal(1); |             settingsSave.callCount.should.equal(1); | ||||||
|             settingsSave.firstCall.args[0].should.be.equal("nodes"); |             settingsSave.firstCall.args[0].should.be.equal("modules"); | ||||||
|             var savedList = settingsSave.firstCall.args[1]; |             var savedList = settingsSave.firstCall.args[1]; | ||||||
|  |  | ||||||
|             savedList[list[0].id].name == list[0].name; |             savedList[moduleList[0].name].name.should.equal(moduleList[0].name); | ||||||
|             savedList[list[1].id].name == list[1].name; |  | ||||||
|             savedList[list[2].id].name == list[2].name; |  | ||||||
|  |  | ||||||
|             savedList[list[0].id].should.not.have.property("err"); |             savedList[moduleList[0].name].nodes[moduleList[0].nodes[0].name].name.should.equal(moduleList[0].nodes[0].name); | ||||||
|             savedList[list[1].id].should.not.have.property("err"); |             savedList[moduleList[0].name].nodes[moduleList[0].nodes[1].name].name.should.equal(moduleList[0].nodes[1].name); | ||||||
|             savedList[list[2].id].should.not.have.property("err"); |             savedList[moduleList[0].name].nodes[moduleList[0].nodes[2].name].name.should.equal(moduleList[0].nodes[2].name); | ||||||
|  |  | ||||||
|  |             savedList[moduleList[0].name].nodes[moduleList[0].nodes[0].name].should.not.have.property("err"); | ||||||
|  |             savedList[moduleList[0].name].nodes[moduleList[0].nodes[1].name].should.not.have.property("err"); | ||||||
|  |             savedList[moduleList[0].name].nodes[moduleList[0].nodes[2].name].should.not.have.property("err"); | ||||||
|  |  | ||||||
|             done(); |             done(); | ||||||
|         }).catch(function(e) { |         }).catch(function(e) { | ||||||
| @@ -336,10 +334,12 @@ describe('NodeRegistry', function() { | |||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.be.empty; |             list.should.be.an.Array.and.be.empty; | ||||||
|  |  | ||||||
|  |             // TODO: Needs module and name params for loadNodeConfig | ||||||
|             typeRegistry.addNode(resourcesDir + "TestNode1/TestNode1.js").then(function(node) { |             typeRegistry.addNode(resourcesDir + "TestNode1/TestNode1.js").then(function(node) { | ||||||
|                 list = typeRegistry.getNodeList(); |                 list = typeRegistry.getNodeList(); | ||||||
|                 list[0].should.have.property("id"); |                 list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|                 list[0].should.have.property("name","TestNode1.js"); |                 list[0].should.have.property("name","TestNode1"); | ||||||
|  |                 list[0].should.have.property("module","node-red"); | ||||||
|                 list[0].should.have.property("types",["test-node-1"]); |                 list[0].should.have.property("types",["test-node-1"]); | ||||||
|                 list[0].should.have.property("enabled",true); |                 list[0].should.have.property("enabled",true); | ||||||
|                 list[0].should.not.have.property("err"); |                 list[0].should.not.have.property("err"); | ||||||
| @@ -386,8 +386,9 @@ describe('NodeRegistry', function() { | |||||||
|             var id = list[0].id; |             var id = list[0].id; | ||||||
|             var type = list[0].types[0]; |             var type = list[0].types[0]; | ||||||
|  |  | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|             list[0].should.have.property("name","TestNode1.js"); |             list[0].should.have.property("name","TestNode1"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-1"]); |             list[0].should.have.property("types",["test-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
| @@ -405,7 +406,7 @@ describe('NodeRegistry', function() { | |||||||
|  |  | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it('returns plugins list', function(done) { |     it('returns modules list', function(done) { | ||||||
|         var fs = require("fs"); |         var fs = require("fs"); | ||||||
|         var path = require("path"); |         var path = require("path"); | ||||||
|  |  | ||||||
| @@ -438,7 +439,7 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load("wontexist",true).then(function(){ |         typeRegistry.load("wontexist",true).then(function(){ | ||||||
|  |  | ||||||
|             typeRegistry.addModule("TestNodeModule").then(function() { |             typeRegistry.addModule("TestNodeModule").then(function() { | ||||||
|                 var list = typeRegistry.getPluginList(); |                 var list = typeRegistry.getModuleList(); | ||||||
|                 list.should.be.an.Array.and.have.lengthOf(1); |                 list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|                 list[0].should.have.property("name", "TestNodeModule"); |                 list[0].should.have.property("name", "TestNodeModule"); | ||||||
|                 list[0].should.have.property("nodes"); |                 list[0].should.have.property("nodes"); | ||||||
| @@ -457,7 +458,7 @@ describe('NodeRegistry', function() { | |||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it('returns plugin info', function(done) { |     it('returns module info', function(done) { | ||||||
|         var fs = require("fs"); |         var fs = require("fs"); | ||||||
|         var path = require("path"); |         var path = require("path"); | ||||||
|  |  | ||||||
| @@ -490,11 +491,11 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load("wontexist",true).then(function(){ |         typeRegistry.load("wontexist",true).then(function(){ | ||||||
|  |  | ||||||
|             typeRegistry.addModule("TestNodeModule").then(function(nodes) { |             typeRegistry.addModule("TestNodeModule").then(function(nodes) { | ||||||
|                 var list = typeRegistry.getPluginList(); |                 var list = typeRegistry.getModuleList(); | ||||||
|  |  | ||||||
|                 var plugin = typeRegistry.getPluginInfo(list[0].name); |                 var module = typeRegistry.getModuleInfo(list[0].name); | ||||||
|                 plugin.should.have.property("name", list[0].name); |                 module.should.have.property("name", list[0].name); | ||||||
|                 plugin.should.have.property("nodes", nodes); |                 module.should.have.property("nodes", nodes); | ||||||
|                 done(); |                 done(); | ||||||
|             }).catch(function(e) { |             }).catch(function(e) { | ||||||
|                 done(e); |                 done(e); | ||||||
| @@ -532,8 +533,9 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load(resourcesDir + "TestNode1",true).then(function() { |         typeRegistry.load(resourcesDir + "TestNode1",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|             list[0].should.have.property("name","TestNode1.js"); |             list[0].should.have.property("name","TestNode1"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-1"]); |             list[0].should.have.property("types",["test-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.have.property("loaded",true); |             list[0].should.have.property("loaded",true); | ||||||
| @@ -552,7 +554,6 @@ describe('NodeRegistry', function() { | |||||||
|             var nodeConstructor = typeRegistry.get("test-node-1"); |             var nodeConstructor = typeRegistry.get("test-node-1"); | ||||||
|             (typeof nodeConstructor).should.be.equal("undefined"); |             (typeof nodeConstructor).should.be.equal("undefined"); | ||||||
|  |  | ||||||
|  |  | ||||||
|             done(); |             done(); | ||||||
|         }).catch(function(e) { |         }).catch(function(e) { | ||||||
|             done(e); |             done(e); | ||||||
| @@ -612,14 +613,16 @@ describe('NodeRegistry', function() { | |||||||
|         typeRegistry.load("wontexist",false).then(function(){ |         typeRegistry.load("wontexist",false).then(function(){ | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(2); |             list.should.be.an.Array.and.have.lengthOf(2); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","TestNodeModule/TestNodeMod1"); | ||||||
|             list[0].should.have.property("name","TestNodeModule:TestNodeMod1"); |             list[0].should.have.property("name","TestNodeMod1"); | ||||||
|  |             list[0].should.have.property("module","TestNodeModule"); | ||||||
|             list[0].should.have.property("types",["test-node-mod-1"]); |             list[0].should.have.property("types",["test-node-mod-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|             list[0].should.not.have.property("err"); |             list[0].should.not.have.property("err"); | ||||||
|  |  | ||||||
|             list[1].should.have.property("id"); |             list[1].should.have.property("id","TestNodeModule/TestNodeMod2"); | ||||||
|             list[1].should.have.property("name","TestNodeModule:TestNodeMod2"); |             list[1].should.have.property("name","TestNodeMod2"); | ||||||
|  |             list[1].should.have.property("module","TestNodeModule"); | ||||||
|             list[1].should.have.property("types",["test-node-mod-2"]); |             list[1].should.have.property("types",["test-node-mod-2"]); | ||||||
|             list[1].should.have.property("enabled",true); |             list[1].should.have.property("enabled",true); | ||||||
|             list[1].should.have.property("err"); |             list[1].should.have.property("err"); | ||||||
| @@ -681,14 +684,16 @@ describe('NodeRegistry', function() { | |||||||
|             typeRegistry.addModule("TestNodeModule").then(function(node) { |             typeRegistry.addModule("TestNodeModule").then(function(node) { | ||||||
|                 list = typeRegistry.getNodeList(); |                 list = typeRegistry.getNodeList(); | ||||||
|                 list.should.be.an.Array.and.have.lengthOf(2); |                 list.should.be.an.Array.and.have.lengthOf(2); | ||||||
|                 list[0].should.have.property("id"); |                 list[0].should.have.property("id","TestNodeModule/TestNodeMod1"); | ||||||
|                 list[0].should.have.property("name","TestNodeModule:TestNodeMod1"); |                 list[0].should.have.property("name","TestNodeMod1"); | ||||||
|  |                 list[0].should.have.property("module","TestNodeModule"); | ||||||
|                 list[0].should.have.property("types",["test-node-mod-1"]); |                 list[0].should.have.property("types",["test-node-mod-1"]); | ||||||
|                 list[0].should.have.property("enabled",true); |                 list[0].should.have.property("enabled",true); | ||||||
|                 list[0].should.not.have.property("err"); |                 list[0].should.not.have.property("err"); | ||||||
|  |  | ||||||
|                 list[1].should.have.property("id"); |                 list[1].should.have.property("id","TestNodeModule/TestNodeMod2"); | ||||||
|                 list[1].should.have.property("name","TestNodeModule:TestNodeMod2"); |                 list[1].should.have.property("name","TestNodeMod2"); | ||||||
|  |                 list[1].should.have.property("module","TestNodeModule"); | ||||||
|                 list[1].should.have.property("types",["test-node-mod-2"]); |                 list[1].should.have.property("types",["test-node-mod-2"]); | ||||||
|                 list[1].should.have.property("enabled",true); |                 list[1].should.have.property("enabled",true); | ||||||
|                 list[1].should.have.property("err"); |                 list[1].should.have.property("err"); | ||||||
| @@ -708,6 +713,60 @@ describe('NodeRegistry', function() { | |||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     it('adds module with version number', function(done) { | ||||||
|  |         var fs = require("fs"); | ||||||
|  |         var path = require("path"); | ||||||
|  |  | ||||||
|  |         var pathJoin = (function() { | ||||||
|  |             var _join = path.join; | ||||||
|  |             return sinon.stub(path,"join",function() { | ||||||
|  |                 if (arguments.length  == 3 && arguments[2] == "package.json") { | ||||||
|  |                     return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1],arguments[2]); | ||||||
|  |                 } | ||||||
|  |                 if (arguments.length == 2 && arguments[1] == "TestNodeModule") { | ||||||
|  |                     return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1]); | ||||||
|  |                 } | ||||||
|  |                 return _join.apply(this,arguments); | ||||||
|  |             }); | ||||||
|  |         })(); | ||||||
|  |  | ||||||
|  |         var readdirSync = (function() { | ||||||
|  |             var originalReaddirSync = fs.readdirSync; | ||||||
|  |             var callCount = 0; | ||||||
|  |             return sinon.stub(fs,"readdirSync",function(dir) { | ||||||
|  |                 var result = []; | ||||||
|  |                 if (callCount == 1) { | ||||||
|  |                     result = originalReaddirSync(resourcesDir + "TestNodeModule" + path.sep + "node_modules"); | ||||||
|  |                 } | ||||||
|  |                 callCount++; | ||||||
|  |                 return result; | ||||||
|  |             }); | ||||||
|  |         })(); | ||||||
|  |         typeRegistry.init(settingsWithStorage); | ||||||
|  |         typeRegistry.load("wontexist",true).then(function(){ | ||||||
|  |             typeRegistry.addModule("TestNodeModule","0.0.1").then(function(node) { | ||||||
|  |                 var module = typeRegistry.getModuleInfo("TestNodeModule"); | ||||||
|  |  | ||||||
|  |                 module.should.have.property("name","TestNodeModule"); | ||||||
|  |                 module.should.have.property("version","0.0.1"); | ||||||
|  |  | ||||||
|  |                 var modules = typeRegistry.getModuleList(); | ||||||
|  |  | ||||||
|  |                 modules[0].should.have.property("name","TestNodeModule"); | ||||||
|  |                 modules[0].should.have.property("version","0.0.1"); | ||||||
|  |  | ||||||
|  |                 done(); | ||||||
|  |             }).catch(function(e) { | ||||||
|  |                 done(e); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |         }).catch(function(e) { | ||||||
|  |             done(e); | ||||||
|  |         }).finally(function() { | ||||||
|  |             readdirSync.restore(); | ||||||
|  |             pathJoin.restore(); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     it('rejects adding duplicate node modules', function(done) { |     it('rejects adding duplicate node modules', function(done) { | ||||||
|         var fs = require("fs"); |         var fs = require("fs"); | ||||||
| @@ -847,13 +906,14 @@ describe('NodeRegistry', function() { | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |  | ||||||
|     it('allows nodes to be enabled and disabled by hex-id', function(done) { |     it('allows nodes to be enabled and disabled by id', function(done) { | ||||||
|         typeRegistry.init(settingsWithStorage); |         typeRegistry.init(settingsWithStorage); | ||||||
|         typeRegistry.load(resourcesDir+path.sep+"TestNode1",true).then(function() { |         typeRegistry.load(resourcesDir+path.sep+"TestNode1",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|             list[0].should.have.property("name","TestNode1.js"); |             list[0].should.have.property("name","TestNode1"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|  |  | ||||||
|             var nodeConfig = typeRegistry.getNodeConfigs(); |             var nodeConfig = typeRegistry.getNodeConfigs(); | ||||||
| @@ -892,8 +952,9 @@ describe('NodeRegistry', function() { | |||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|  |  | ||||||
|             list.should.be.an.Array.and.have.lengthOf(1); |             list.should.be.an.Array.and.have.lengthOf(1); | ||||||
|             list[0].should.have.property("id"); |             list[0].should.have.property("id","node-red/TestNode1"); | ||||||
|             list[0].should.have.property("name","TestNode1.js"); |             list[0].should.have.property("name","TestNode1"); | ||||||
|  |             list[0].should.have.property("module","node-red"); | ||||||
|             list[0].should.have.property("types",["test-node-1"]); |             list[0].should.have.property("types",["test-node-1"]); | ||||||
|             list[0].should.have.property("enabled",true); |             list[0].should.have.property("enabled",true); | ||||||
|  |  | ||||||
| @@ -930,7 +991,7 @@ describe('NodeRegistry', function() { | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it('fails to enable/disable non-existent nodes', function(done) { |     it('fails to enable/disable non-existent nodes', function(done) { | ||||||
|         typeRegistry.init(settings); |         typeRegistry.init(settingsWithStorage); | ||||||
|         typeRegistry.load("wontexist",true).then(function() { |         typeRegistry.load("wontexist",true).then(function() { | ||||||
|             var list = typeRegistry.getNodeList(); |             var list = typeRegistry.getNodeList(); | ||||||
|             list.should.be.an.Array.and.be.empty; |             list.should.be.an.Array.and.be.empty; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user