Fix license issues
[sdnc/oam.git] / dgbuilder / red / nodes / registry.js
diff --git a/dgbuilder/red/nodes/registry.js b/dgbuilder/red/nodes/registry.js
deleted file mode 100644 (file)
index f2073af..0000000
+++ /dev/null
@@ -1,693 +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 util = require("util");
-var when = require("when");
-var whenNode = require('when/node');
-var fs = require("fs");
-var path = require("path");
-var crypto = require("crypto"); 
-var UglifyJS = require("uglify-js");
-
-var events = require("../events");
-
-var Node;
-var settings;
-
-function filterNodeInfo(n) {
-    var r = {
-        id: n.id,
-        name: n.name,
-        types: n.types,
-        enabled: n.enabled
-    }
-    if (n.hasOwnProperty("loaded")) {
-        r.loaded = n.loaded;
-    }
-    if (n.hasOwnProperty("module")) {
-        r.module = n.module;
-    }
-    if (n.hasOwnProperty("err")) {
-        r.err = n.err.toString();
-    }
-    return r;
-}
-
-var registry = (function() {
-    var nodeConfigCache = null;
-    var nodeConfigs = {};
-    var nodeList = [];
-    var nodeConstructors = {};
-    var nodeTypeToId = {};
-    var nodeModules = {};
-    
-    function saveNodeList() {
-        var nodeList = {};
-        
-        for (var i in nodeConfigs) {
-            if (nodeConfigs.hasOwnProperty(i)) {
-                var nodeConfig = nodeConfigs[i];
-                var n = filterNodeInfo(nodeConfig);
-                n.file = nodeConfig.file;
-                delete n.loaded;
-                delete n.err;
-                delete n.file;
-                delete n.id;
-                nodeList[i] = n;
-            }
-        }
-        if (settings.available()) {
-            return settings.set("nodes",nodeList);
-        } else {
-            return when.reject("Settings unavailable");
-        }
-    }
-    
-    return {
-        init: function() {
-            if (settings.available()) {
-                nodeConfigs = settings.get("nodes")||{};
-                // Restore the node id property to individual entries
-                for (var id in nodeConfigs) {
-                    if (nodeConfigs.hasOwnProperty(id)) {
-                        nodeConfigs[id].id = id;
-                    }
-                }
-            } else {
-                nodeConfigs = {};
-            }
-            nodeModules = {};
-            nodeTypeToId = {};
-            nodeConstructors = {};
-            nodeList = [];
-            nodeConfigCache = null;
-        },
-        
-        addNodeSet: function(id,set) {
-            if (!set.err) {
-                set.types.forEach(function(t) {
-                    nodeTypeToId[t] = id;
-                });
-            }
-            
-            if (set.module) {
-                nodeModules[set.module] = nodeModules[set.module]||{nodes:[]};
-                nodeModules[set.module].nodes.push(id);
-            }
-            
-            nodeConfigs[id] = set;
-            nodeList.push(id);
-            nodeConfigCache = null;
-        },
-        removeNode: function(id) {
-            var config = nodeConfigs[id];
-            if (!config) {
-                throw new Error("Unrecognised id: "+id);
-            }
-            delete nodeConfigs[id];
-            var i = nodeList.indexOf(id);
-            if (i > -1) {
-                nodeList.splice(i,1);
-            }
-            config.types.forEach(function(t) {
-                delete nodeConstructors[t];
-                delete nodeTypeToId[t];
-            });
-            config.enabled = false;
-            config.loaded = false;
-            nodeConfigCache = null;
-            return filterNodeInfo(config);
-        },
-        removeModule: function(module) {
-            if (!settings.available()) {
-                throw new Error("Settings unavailable");
-            }
-            var nodes = nodeModules[module];
-            if (!nodes) {
-                throw new Error("Unrecognised module: "+module);
-            }
-            var infoList = [];
-            for (var i=0;i<nodes.nodes.length;i++) {
-                infoList.push(registry.removeNode(nodes.nodes[i]));
-            }
-            delete nodeModules[module];
-            saveNodeList();
-            return infoList;
-        },
-        getNodeInfo: function(typeOrId) {
-            if (nodeTypeToId[typeOrId]) {
-                return filterNodeInfo(nodeConfigs[nodeTypeToId[typeOrId]]);
-            } else if (nodeConfigs[typeOrId]) {
-                return filterNodeInfo(nodeConfigs[typeOrId]);
-            }
-            return null;
-        },
-        getNodeList: function() {
-            var list = [];
-            for (var id in nodeConfigs) {
-                if (nodeConfigs.hasOwnProperty(id)) {
-                    list.push(filterNodeInfo(nodeConfigs[id]))
-                }
-            }
-            return list;
-        },
-        registerNodeConstructor: function(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
-            util.inherits(constructor,Node);
-            nodeConstructors[type] = constructor;
-            events.emit("type-registered",type);
-        },
-        
-        
-        /**
-         * Gets all of the node template configs
-         * @return all of the node templates in a single string
-         */
-        getAllNodeConfigs: function() {
-            if (!nodeConfigCache) {
-                var result = "";
-                var script = "";
-                for (var i=0;i<nodeList.length;i++) {
-                    var config = nodeConfigs[nodeList[i]];
-                    if (config.enabled && !config.err) {
-                        result += config.config;
-                        script += config.script;
-                    }
-                }
-                if (script.length > 0) {
-                    result += '<script type="text/javascript">';
-                    result += UglifyJS.minify(script, {fromString: true}).code;
-                    result += '</script>';
-                }
-                nodeConfigCache = result;
-            }
-            return nodeConfigCache;
-        },
-        
-        getNodeConfig: function(id) {
-            var config = nodeConfigs[id];
-            if (config) {
-                var result = config.config;
-                if (config.script) {
-                    result += '<script type="text/javascript">'+config.script+'</script>';
-                }
-                return result;
-            } else {
-                return null;
-            }
-        },
-        
-        getNodeConstructor: function(type) {
-            var config = nodeConfigs[nodeTypeToId[type]];
-            if (!config || (config.enabled && !config.err)) {
-                return nodeConstructors[type];
-            }
-            return null;
-        },
-        
-        clear: function() {
-            nodeConfigCache = null;
-            nodeConfigs = {};
-            nodeList = [];
-            nodeConstructors = {};
-            nodeTypeToId = {};
-        },
-        
-        getTypeId: function(type) {
-            return nodeTypeToId[type];
-        },
-        
-        getModuleInfo: function(type) {
-            return nodeModules[type];
-        },
-        
-        enableNodeSet: function(id) {
-            if (!settings.available()) {
-                throw new Error("Settings unavailable");
-            }
-            var config = nodeConfigs[id];
-            if (config) {
-                delete config.err;
-                config.enabled = true;
-                if (!config.loaded) {
-                    // TODO: honour the promise this returns
-                    loadNodeModule(config);
-                }
-                nodeConfigCache = null;
-                saveNodeList();
-            } else {
-                throw new Error("Unrecognised id: "+id);
-            }
-            return filterNodeInfo(config);
-        },
-        
-        disableNodeSet: function(id) {
-            if (!settings.available()) {
-                throw new Error("Settings unavailable");
-            }
-            var config = nodeConfigs[id];
-            if (config) {
-                // TODO: persist setting
-                config.enabled = false;
-                nodeConfigCache = null;
-                saveNodeList();
-            } else {
-                throw new Error("Unrecognised id: "+id);
-            }
-            return filterNodeInfo(config);
-        },
-        
-        saveNodeList: saveNodeList,
-        
-        cleanNodeList: function() {
-            var removed = false;
-            for (var id in nodeConfigs) {
-                if (nodeConfigs.hasOwnProperty(id)) {
-                    if (nodeConfigs[id].module && !nodeModules[nodeConfigs[id].module]) {
-                        registry.removeNode(id);
-                        removed = true;
-                    }
-                }
-            }
-            if (removed) {
-                saveNodeList();
-            }
-        }
-    }
-})();
-
-
-
-function init(_settings) {
-    Node = require("./Node");
-    settings = _settings;
-    registry.init();
-}
-
-/**
- * Synchronously walks the directory looking for node files.
- * Emits 'node-icon-dir' events for an icon dirs found
- * @param dir the directory to search
- * @return an array of fully-qualified paths to .js files
- */
-function getNodeFiles(dir) {
-    var result = [];
-    var files = [];
-    try {
-        files = fs.readdirSync(dir);
-    } catch(err) {
-        return result;
-    }
-    files.sort();
-    files.forEach(function(fn) {
-        var stats = fs.statSync(path.join(dir,fn));
-        if (stats.isFile()) {
-            if (/\.js$/.test(fn)) {
-                var valid = true;
-                if (settings.nodesExcludes) {
-                    for (var i=0;i<settings.nodesExcludes.length;i++) {
-                        if (settings.nodesExcludes[i] == fn) {
-                            valid = false;
-                            break;
-                        }
-                    }
-                }
-                valid = valid && fs.existsSync(path.join(dir,fn.replace(/\.js$/,".html")))
-                
-                if (valid) {
-                    result.push(path.join(dir,fn));
-                }
-            }
-        } else if (stats.isDirectory()) {
-            // Ignore /.dirs/, /lib/ /node_modules/ 
-            if (!/^(\..*|lib|icons|node_modules|test)$/.test(fn)) {
-                result = result.concat(getNodeFiles(path.join(dir,fn)));
-            } else if (fn === "icons") {
-                events.emit("node-icon-dir",path.join(dir,fn));
-            }
-        }
-    });
-    return result;
-}
-
-/**
- * Scans the node_modules path for nodes
- * @param moduleName the name of the module to be found
- * @return a list of node modules: {dir,package}
- */
-function scanTreeForNodesModules(moduleName) {
-    var dir = __dirname+"/../../nodes";
-    var results = [];
-    var up = path.resolve(path.join(dir,".."));
-    while (up !== dir) {
-        var pm = path.join(dir,"node_modules");
-        try {
-            var files = fs.readdirSync(pm);
-            for (var i=0;i<files.length;i++) {
-                var fn = files[i];
-                if (!registry.getModuleInfo(fn)) {
-                    if (!moduleName || fn == moduleName) {
-                        var pkgfn = path.join(pm,fn,"package.json");
-                        try {
-                            var pkg = require(pkgfn);
-                            if (pkg['node-red']) {
-                                var moduleDir = path.join(pm,fn);
-                                results.push({dir:moduleDir,package:pkg});
-                            }
-                        } catch(err) {
-                            if (err.code != "MODULE_NOT_FOUND") {
-                                // TODO: handle unexpected error
-                            }
-                        }
-                        if (fn == moduleName) {
-                            break;
-                        }
-                    }
-                }
-            }
-        } catch(err) {
-        }
-        
-        dir = up;
-        up = path.resolve(path.join(dir,".."));
-    }
-    return results;
-}
-
-/**
- * Loads the nodes provided in an npm package.
- * @param moduleDir the root directory of the package
- * @param pkg the module's package.json object
- */
-function loadNodesFromModule(moduleDir,pkg) {
-    var nodes = pkg['node-red'].nodes||{};
-    var results = [];
-    var iconDirs = [];
-    for (var n in nodes) {
-        if (nodes.hasOwnProperty(n)) {
-            var file = path.join(moduleDir,nodes[n]);
-            try {
-                results.push(loadNodeConfig(file,pkg.name,n));
-            } catch(err) {
-            }
-            var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons");
-            if (iconDirs.indexOf(iconDir) == -1) {
-                if (fs.existsSync(iconDir)) {
-                    events.emit("node-icon-dir",iconDir);
-                    iconDirs.push(iconDir);
-                }
-            }
-        }
-    }
-    return results;
-}
-
-
-/**
- * Loads a node's configuration
- * @param file the fully qualified path of the node's .js file
- * @param name the name of the node
- * @return the node object
- *         {
- *            id: a unqiue id for the node file
- *            name: the name of the node file, or label from the npm module
- *            file: the fully qualified path to the node's .js file
- *            template: the fully qualified path to the node's .html file
- *            config: the non-script parts of the node's .html file
- *            script: the script part of the node's .html file
- *            types: an array of node type names in this file
- *         }
- */
-function loadNodeConfig(file,module,name) {
-    var id = crypto.createHash('sha1').update(file).digest("hex");
-    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 isEnabled = true;
-
-    if (info) {
-        if (info.hasOwnProperty("loaded")) {
-            throw new Error(file+" already loaded");
-        }
-        isEnabled = info.enabled;
-    }
-    
-    var node = {
-        id: id,
-        file: file,
-        template: file.replace(/\.js$/,".html"),
-        enabled: isEnabled,
-        loaded:false
-    }
-    
-    if (module) {
-        node.name = module+":"+name;
-        node.module = module;
-    } else {
-        node.name = path.basename(file)
-    }
-    try {
-        var content = fs.readFileSync(node.template,'utf8');
-        
-        var types = [];
-        
-        var regExp = /<script ([^>]*)data-template-name=['"]([^'"]*)['"]/gi;
-        var match = null;
-        
-        while((match = regExp.exec(content)) !== null) {
-            types.push(match[2]);
-        }
-        node.types = types;
-        node.config = content;
-        
-        // TODO: parse out the javascript portion of the template
-        node.script = "";
-        
-        for (var i=0;i<node.types.length;i++) {
-            if (registry.getTypeId(node.types[i])) {
-                node.err = node.types[i]+" already registered";
-                break;
-            }
-        }
-    } catch(err) {
-        node.types = [];
-        if (err.code === 'ENOENT') {
-            node.err = "Error: "+file+" does not exist";
-        } else {
-            node.err = err.toString();
-        }
-    }
-    registry.addNodeSet(id,node);
-    return node;
-}
-
-/**
- * Loads all palette nodes
- * @param defaultNodesDir optional parameter, when set, it overrides the default
- *                        location of nodeFiles - used by the tests
- * @return a promise that resolves on completion of loading
- */
-function load(defaultNodesDir,disableNodePathScan) {
-    return when.promise(function(resolve,reject) {
-        // Find all of the nodes to load
-        var nodeFiles;
-        if(defaultNodesDir) {
-            nodeFiles = getNodeFiles(path.resolve(defaultNodesDir));
-        } else {
-            nodeFiles = getNodeFiles(__dirname+"/../../nodes");
-        }
-        
-        if (settings.nodesDir) {
-            var dir = settings.nodesDir;
-            if (typeof settings.nodesDir == "string") {
-                dir = [dir];
-            }
-            for (var i=0;i<dir.length;i++) {
-                nodeFiles = nodeFiles.concat(getNodeFiles(dir[i]));
-            }
-        }
-        var nodes = [];
-        nodeFiles.forEach(function(file) {
-            try {
-                nodes.push(loadNodeConfig(file));
-            } catch(err) {
-                // 
-            }
-        });
-        
-        // TODO: disabling npm module loading if defaultNodesDir set
-        //       This indicates a test is being run - don't want to pick up
-        //       unexpected nodes.
-        //       Urgh.
-        if (!disableNodePathScan) {
-            // Find all of the modules containing nodes
-            var moduleFiles = scanTreeForNodesModules();
-            moduleFiles.forEach(function(moduleFile) {
-                nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package));
-            });
-        }
-        var promises = [];
-        nodes.forEach(function(node) {
-            if (!node.err) {
-                promises.push(loadNodeModule(node));
-            }
-        });
-        
-        //resolve([]);
-        when.settle(promises).then(function(results) {
-            // Trigger a load of the configs to get it precached
-            registry.getAllNodeConfigs();
-            
-            if (settings.available()) {
-                resolve(registry.saveNodeList());
-            } else {
-                resolve();
-            }
-        }); 
-    });
-}
-
-/**
- * Loads the specified node into the runtime
- * @param node a node info object - see loadNodeConfig
- * @return a promise that resolves to an update node info object. The object
- *         has the following properties added:
- *            err: any error encountered whilst loading the node
- *            
- */
-function loadNodeModule(node) {
-    var nodeDir = path.dirname(node.file);
-    var nodeFn = path.basename(node.file);
-    if (!node.enabled) {
-        return when.resolve(node);
-    }
-    try {
-        var loadPromise = null;
-        var r = require(node.file);
-        if (typeof r === "function") {
-            var promise = r(require('../red'));
-            if (promise != null && typeof promise.then === "function") {
-                loadPromise = promise.then(function() {
-                    node.enabled = true;
-                    node.loaded = true;
-                    return node;
-                }).otherwise(function(err) {
-                    node.err = err;
-                    return node;
-                });
-            }
-        }
-        if (loadPromise == null) {
-            node.enabled = true;
-            node.loaded = true;
-            loadPromise = when.resolve(node);
-        }
-        return loadPromise;
-    } catch(err) {
-        node.err = err;
-        return when.resolve(node);
-    }
-}
-
-function loadNodeList(nodes) {
-    var promises = [];
-    nodes.forEach(function(node) {
-        if (!node.err) {
-            promises.push(loadNodeModule(node));
-        } else {
-            promises.push(node);
-        }
-    });
-    
-    return when.settle(promises).then(function(results) {
-        return registry.saveNodeList().then(function() {
-            var list = results.map(function(r) {
-                return filterNodeInfo(r.value);
-            });
-            return list;
-        });
-    });
-}
-
-function addNode(file) {
-    if (!settings.available()) {
-        throw new Error("Settings unavailable");
-    }
-    var nodes = [];
-    try { 
-        nodes.push(loadNodeConfig(file));
-    } catch(err) {
-        return when.reject(err);
-    }
-    return loadNodeList(nodes);
-}
-
-function addModule(module) {
-    if (!settings.available()) {
-        throw new Error("Settings unavailable");
-    }
-    var nodes = [];
-    if (registry.getModuleInfo(module)) {
-        return when.reject(new Error("Module already loaded"));
-    }
-    var moduleFiles = scanTreeForNodesModules(module);
-    if (moduleFiles.length === 0) {
-        var err = new Error("Cannot find module '" + module + "'");
-        err.code = 'MODULE_NOT_FOUND';
-        return when.reject(err);
-    }
-    moduleFiles.forEach(function(moduleFile) {
-        nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package));
-    });
-    return loadNodeList(nodes);
-}
-
-module.exports = {
-    init:init,
-    load:load,
-    clear: registry.clear,
-    registerType: registry.registerNodeConstructor,
-    get: registry.getNodeConstructor,
-    getNodeInfo: registry.getNodeInfo,
-    getNodeModuleInfo: registry.getModuleInfo,
-    getNodeList: registry.getNodeList,
-    getNodeConfigs: registry.getAllNodeConfigs,
-    getNodeConfig: registry.getNodeConfig,
-    addNode: addNode,
-    removeNode: registry.removeNode,
-    enableNode: registry.enableNodeSet,
-    disableNode: registry.disableNodeSet,
-    
-    addModule: addModule,
-    removeModule: registry.removeModule,
-    cleanNodeList: registry.cleanNodeList
-}