/** * Copyright 2015 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * 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 UglifyJS = require("uglify-js"); var util = require("util"); var when = require("when"); var events = require("../../events"); var settings; var Node; var loader; var nodeConfigCache = null; var moduleConfigs = {}; var nodeList = []; var nodeConstructors = {}; var nodeTypeToId = {}; var moduleNodes = {}; function init(_settings,_loader) { settings = _settings; loader = _loader; if (settings.available()) { moduleConfigs = loadNodeConfigs(); } else { moduleConfigs = {}; } moduleNodes = {}; nodeTypeToId = {}; nodeConstructors = {}; nodeList = []; nodeConfigCache = null; Node = require("../Node"); } function filterNodeInfo(n) { var r = { id: n.id||n.module+"/"+n.name, name: n.name, types: n.types, enabled: n.enabled }; if (n.hasOwnProperty("module")) { r.module = n.module; } if (n.hasOwnProperty("err")) { r.err = n.err.toString(); } return r; } function getModule(id) { return id.split("/")[0]; } function getNode(id) { return id.split("/")[1]; } function saveNodeList() { var moduleList = {}; for (var module in moduleConfigs) { /* istanbul ignore else */ if (moduleConfigs.hasOwnProperty(module)) { if (Object.keys(moduleConfigs[module].nodes).length > 0) { if (!moduleList[module]) { moduleList[module] = { name: module, version: moduleConfigs[module].version, nodes: {} }; } var nodes = moduleConfigs[module].nodes; for(var node in nodes) { /* istanbul ignore else */ if (nodes.hasOwnProperty(node)) { var config = nodes[node]; var n = filterNodeInfo(config); delete n.err; delete n.file; delete n.id; n.file = config.file; moduleList[module].nodes[node] = n; } } } } } if (settings.available()) { return settings.set("nodes",moduleList); } else { return when.reject("Settings unavailable"); } } function loadNodeConfigs() { var configs = settings.get("nodes"); if (!configs) { return {}; } else if (configs['node-red']) { return configs; } else { // Migrate from the 0.9.1 format of settings var newConfigs = {}; for (var id in configs) { /* istanbul ignore else */ if (configs.hasOwnProperty(id)) { var nodeConfig = configs[id]; var moduleName; var nodeSetName; if (nodeConfig.module) { moduleName = nodeConfig.module; nodeSetName = nodeConfig.name.split(":")[1]; } else { moduleName = "node-red"; nodeSetName = nodeConfig.name.replace(/^\d+-/,"").replace(/\.js$/,""); } if (!newConfigs[moduleName]) { newConfigs[moduleName] = { name: moduleName, nodes:{} }; } newConfigs[moduleName].nodes[nodeSetName] = { name: nodeSetName, types: nodeConfig.types, enabled: nodeConfig.enabled, module: moduleName }; } } settings.set("nodes",newConfigs); return newConfigs; } } function addNodeSet(id,set,version) { if (!set.err) { set.types.forEach(function(t) { nodeTypeToId[t] = id; }); } moduleNodes[set.module] = moduleNodes[set.module]||[]; moduleNodes[set.module].push(set.name); if (!moduleConfigs[set.module]) { moduleConfigs[set.module] = { name: set.module, nodes: {} }; } if (version) { moduleConfigs[set.module].version = version; } moduleConfigs[set.module].nodes[set.name] = set; nodeList.push(id); nodeConfigCache = null; } function removeNode(id) { var config = moduleConfigs[getModule(id)].nodes[getNode(id)]; if (!config) { throw new Error("Unrecognised id: "+id); } delete moduleConfigs[getModule(id)].nodes[getNode(id)]; var i = nodeList.indexOf(id); if (i > -1) { nodeList.splice(i,1); } config.types.forEach(function(t) { var typeId = nodeTypeToId[t]; if (typeId === id) { delete nodeConstructors[t]; delete nodeTypeToId[t]; } }); config.enabled = false; config.loaded = false; nodeConfigCache = null; return filterNodeInfo(config); } function removeModule(module) { if (!settings.available()) { throw new Error("Settings unavailable"); } var nodes = moduleNodes[module]; if (!nodes) { throw new Error("Unrecognised module: "+module); } var infoList = []; for (var i=0;i= node v5.0.0 // which should be changed when support for node < v5.0.0 is dropped // see: https://github.com/nodejs/node/pull/3455 proto.constructor.super_ = Node; if(Object.setPrototypeOf) { Object.setPrototypeOf(proto, Node.prototype); } else { // hack for node v0.10 proto.__proto__ = Node.prototype; } } } function registerNodeConstructor(type,constructor) { if (nodeConstructors[type]) { throw new Error(type+" already registered"); } //TODO: Ensure type is known - but doing so will break some tests // that don't have a way to register a node template ahead // of registering the constructor if(!(constructor.prototype instanceof Node)) { inheritNode(constructor); } nodeConstructors[type] = constructor; events.emit("type-registered",type); } function getAllNodeConfigs(lang) { if (!nodeConfigCache) { var result = ""; var script = ""; for (var i=0;i 0) { // result += ''; //} nodeConfigCache = result; } return nodeConfigCache; } function getNodeConfig(id,lang) { var config = moduleConfigs[getModule(id)]; if (!config) { return null; } config = config.nodes[getNode(id)]; if (config) { var result = config.config; result += loader.getNodeHelp(config,lang||"en-US") //if (config.script) { // result += ''; //} return result; } else { return null; } } function getNodeConstructor(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)) { return nodeConstructors[type]; } return null; } function clear() { nodeConfigCache = null; moduleConfigs = {}; nodeList = []; nodeConstructors = {}; nodeTypeToId = {}; } function getTypeId(type) { return nodeTypeToId[type]; } function enableNodeSet(typeOrId) { if (!settings.available()) { throw new Error("Settings unavailable"); } var id = typeOrId; if (nodeTypeToId[typeOrId]) { id = nodeTypeToId[typeOrId]; } var config; try { config = moduleConfigs[getModule(id)].nodes[getNode(id)]; delete config.err; config.enabled = true; nodeConfigCache = null; return saveNodeList().then(function() { return filterNodeInfo(config); }); } catch (err) { throw new Error("Unrecognised id: "+typeOrId); } } function disableNodeSet(typeOrId) { if (!settings.available()) { throw new Error("Settings unavailable"); } var id = typeOrId; if (nodeTypeToId[typeOrId]) { id = nodeTypeToId[typeOrId]; } var config; try { config = moduleConfigs[getModule(id)].nodes[getNode(id)]; // TODO: persist setting config.enabled = false; nodeConfigCache = null; return saveNodeList().then(function() { return filterNodeInfo(config); }); } catch (err) { throw new Error("Unrecognised id: "+id); } } function cleanModuleList() { var removed = false; for (var mod in moduleConfigs) { /* istanbul ignore else */ if (moduleConfigs.hasOwnProperty(mod)) { var nodes = moduleConfigs[mod].nodes; var node; if (mod == "node-red") { // For core nodes, look for nodes that are enabled, !loaded and !errored for (node in nodes) { /* istanbul ignore else */ if (nodes.hasOwnProperty(node)) { var n = nodes[node]; if (n.enabled && !n.err && !n.loaded) { removeNode(mod+"/"+node); removed = true; } } } } else { if (moduleConfigs[mod] && !moduleNodes[mod]) { // For node modules, look for missing ones for (node in nodes) { /* istanbul ignore else */ if (nodes.hasOwnProperty(node)) { removeNode(mod+"/"+node); removed = true; } } delete moduleConfigs[mod]; } } } } if (removed) { saveNodeList(); } } var registry = module.exports = { init: init, clear: clear, registerNodeConstructor: registerNodeConstructor, getNodeConstructor: getNodeConstructor, addNodeSet: addNodeSet, enableNodeSet: enableNodeSet, disableNodeSet: disableNodeSet, removeModule: removeModule, getNodeInfo: getNodeInfo, getFullNodeInfo: getFullNodeInfo, getNodeList: getNodeList, getModuleList: getModuleList, getModuleInfo: getModuleInfo, /** * Gets all of the node template configs * @return all of the node templates in a single string */ getAllNodeConfigs: getAllNodeConfigs, getNodeConfig: getNodeConfig, getTypeId: getTypeId, saveNodeList: saveNodeList, cleanModuleList: cleanModuleList };