UNPKG

devebot

Version:

Nodejs Microservice Framework

310 lines (308 loc) 9.7 kB
"use strict"; const Promise = require("bluebird"); const lodash = require("lodash"); const DEFAULT_PORTLET_NAME = "default"; const PORTLETS_COLLECTION_NAME = "portlets"; function createPortletifier() { function Service(params = {}) { const { sandboxBaseConfig, sandboxConfig } = params; // let pluginConfig; // this.getPluginConfig = function () { pluginConfig = pluginConfig || portletifyConfig(sandboxConfig); return pluginConfig; }; // this.getPortletDescriptors = function (selectedPortlets) { return _filterPortletDescriptors(this.getPluginConfig(), selectedPortlets); }; // this.getPortletBaseConfig = function () { return sandboxBaseConfig; }; } // return Service; } function getPortletDescriptors(sandboxConfig, selectedPortlets) { return _filterPortletDescriptors(portletifyConfig(sandboxConfig), selectedPortlets); } function _filterPortletDescriptors(pluginConfig, selectedPortlets) { let portletDescriptors = lodash.get(pluginConfig, PORTLETS_COLLECTION_NAME); if (lodash.isArray(selectedPortlets)) { portletDescriptors = lodash.pick(portletDescriptors, selectedPortlets); } // const ok = strictPortletConfig(portletDescriptors); if (!ok) { throw _newError("DuplicatedPortsInDescriptors", { message: "pluginConfig.portlets has duplicated ports", payload: {} }); } // return portletDescriptors; } function portletifyConfig(sandboxConfig, globalFieldNames) { if (!lodash.isPlainObject(sandboxConfig)) { throw _newError("InvalidSandboxConfigError", { message: "sandboxConfig must be an object", payload: { sandboxConfig } }); } // if (!lodash.has(sandboxConfig, PORTLETS_COLLECTION_NAME)) { lodash.set(sandboxConfig, PORTLETS_COLLECTION_NAME, {}); } const portlets = lodash.get(sandboxConfig, PORTLETS_COLLECTION_NAME); // globalFieldNames = globalFieldNames || []; if (!globalFieldNames.includes(PORTLETS_COLLECTION_NAME)) { globalFieldNames.push(PORTLETS_COLLECTION_NAME); } const defaultPortletConfig = lodash.omit(sandboxConfig, globalFieldNames); // if (lodash.has(portlets, DEFAULT_PORTLET_NAME)) { lodash.defaultsDeep(portlets[DEFAULT_PORTLET_NAME], defaultPortletConfig); return lodash.omit(sandboxConfig, lodash.keys(defaultPortletConfig)); } else { if (lodash.size(defaultPortletConfig) > 0 || lodash.size(portlets) == 0) { lodash.set(portlets, DEFAULT_PORTLET_NAME, defaultPortletConfig); return lodash.omit(sandboxConfig, lodash.keys(defaultPortletConfig)); } } // return sandboxConfig; } function strictPortletConfig(portlets) { const counter = {}; for (let portletId in portlets) { const portletDescriptor = portlets[portletId]; if (lodash.get(portletDescriptor, "enabled") == false) { continue; } if (lodash.get(portletDescriptor, ["__metadata__", "enabled"]) == false) { continue; } if (lodash.has(portletDescriptor, "port")) { const counterId = "" + portletDescriptor.port; counter[counterId] = counter[counterId] || 0; counter[counterId] += 1; } } // const dup = lodash.filter(lodash.values(counter), function (count) { return count > 1; }); // return lodash.size(dup) == 0; } /** * portletForwarder is an interface with hasPortlet() method * portletArguments ~ { L, T, blockRef } * @param {*} params */ function PortletMixiner(params = {}) { const self = this; this._portlets = {}; this._aliases = {}; // let { portletBaseConfig, portletDescriptors } = params; const { portletReferenceHolders, portletArguments, PortletConstructor } = params; // const { pluginConfig, portletCommonConfig, portletForwarder } = params; let { portletAvailableChecker } = params; // portletBaseConfig = portletBaseConfig || portletCommonConfig || {}; // if (lodash.isNil(portletDescriptors)) { if (lodash.isNil(pluginConfig)) { throw _newError("UndefinedPortletDescriptors", { message: "portletDescriptors or pluginConfig must be declared" }); } else { // @deprecated if (!(PORTLETS_COLLECTION_NAME in pluginConfig)) { throw _newError("InvalidPluginConfigPortlets", { message: "pluginConfig.portlets not found", payload: { fieldName: PORTLETS_COLLECTION_NAME } }); } portletDescriptors = lodash.get(pluginConfig, PORTLETS_COLLECTION_NAME); } } if (!lodash.isPlainObject(portletDescriptors)) { throw _newError("InvalidPortletDescriptors", { message: "portletDescriptors must be an object" }); } // if (portletReferenceHolders && !lodash.isPlainObject(portletReferenceHolders)) { throw _newError("InvalidPortletReferenceHolders", { message: "portletReferenceHolders must be a plain object" }); } // portletAvailableChecker = portletAvailableChecker || function (portletName) { return hasPortletOf(portletForwarder, portletName); }; // lodash.forOwn(portletDescriptors, function (portletDescriptor, portletKey) { if (portletDescriptor.enabled !== false) { const portletName = lodash.get(portletDescriptor, ["__metadata__", "name"], portletKey); if (portletName != portletKey) { self._aliases[portletKey] = portletName; } const portletConfig = lodash.merge({}, portletBaseConfig, lodash.omit(portletDescriptor, "__metadata__", {})); // const portletDependencies = {}; for (const portletReferenceName in portletReferenceHolders) { const referenceHolder = portletReferenceHolders[portletReferenceName]; if (referenceHolder && referenceHolder.hasPortlet && referenceHolder.hasPortlet(portletName)) { portletDependencies[portletReferenceName] = referenceHolder.getPortlet(portletName); } } const isPortletAvailable = lodash.size(portletDependencies) == lodash.size(portletReferenceHolders); // self._portlets[portletName] = { available: portletAvailableChecker(portletName) && isPortletAvailable, processor: new PortletConstructor(Object.assign({ portletConfig, portletName }, portletDependencies, portletArguments || {})) }; } }); // this._strictMode = lodash.get(params, "strictMode", false); } PortletMixiner.prototype.getPortletNames = function () { return lodash.keys(this._portlets); }; PortletMixiner.prototype.resolvePortletName = function (portletName) { return this._aliases[portletName] || portletName || DEFAULT_PORTLET_NAME; }; PortletMixiner.prototype.hasPortlet = function (portletName) { portletName = this.resolvePortletName(portletName); return this._portlets[portletName] && this._portlets[portletName].available || false; }; PortletMixiner.prototype.getPortlet = function (portletName) { portletName = this.resolvePortletName(portletName); const processor = this._portlets[portletName] && this._portlets[portletName].processor; if (!processor) { if (this._strictMode) { throw _newError("PortletNotFoundError", { payload: { portletName, availablePortlets: lodash.keys(this._portlets) } }); } return undefined; } return processor; }; PortletMixiner.prototype.eachPortlets = function (iteratee, portletNames) { if (!lodash.isFunction(iteratee)) { return Promise.reject(_newError("InvalidArgumentError", { message: "The first argument must be a function", payload: { type: typeof iteratee, value: iteratee } })); } // if (lodash.isNil(portletNames)) { portletNames = this.getPortletNames(); } if (lodash.isString(portletNames)) { if (!(portletNames in this._portlets)) { return Promise.reject(_newError("InvalidArgumentError", { message: "The second argument is not an available portlet", payload: { type: typeof portletNames, value: portletNames } })); } portletNames = [portletNames]; } if (!lodash.isArray(portletNames)) { return Promise.reject(_newError("InvalidArgumentError", { message: "The second argument must be an array", payload: { type: typeof portletNames, value: portletNames } })); } // const selectedPortletNames = []; const notfoundPortletNames = []; for (const portletName of portletNames) { if (this.hasPortlet(portletName)) { selectedPortletNames.push(portletName); } else { notfoundPortletNames.push(portletName); } } // if (notfoundPortletNames.length > 0 && this._strictMode) { return Promise.reject(_newError("InvalidArgumentError", { message: "There are some portlet names are not available", payload: { selectedPortletNames, notfoundPortletNames } })); } // const self = this; return Promise.mapSeries(selectedPortletNames, function (portletName) { return iteratee(self.getPortlet(portletName), portletName); }); }; function hasPortletOf(portletForwarder, portletName) { if (portletForwarder && lodash.isFunction(portletForwarder.hasPortlet)) { return portletForwarder.hasPortlet(portletName); } return true; } function _newError(name, options) { options = options || {}; const err = new Error(options.message); err.name = name; err.payload = options.payload; return err; } module.exports = { DEFAULT_PORTLET_NAME, PORTLETS_COLLECTION_NAME, createPortletifier, getPortletDescriptors, portletifyConfig, strictPortletConfig, PortletMixiner };