UNPKG

@lager/lager

Version:

AWS Lambda / API Gateway / Endpoint Router

211 lines (184 loc) 6.12 kB
'use strict'; const path = require('path'); const Promise = require('bluebird'); const _ = require('lodash'); const Pebo = require('pebo'); Pebo.setPromise(Promise); const log = require('./log'); Promise.config({ longStackTraces: true }); process.on('uncaughtException', (e) => { log.fatal(e, 'Uncaught Exception'); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { log.fatal({ promise: promise, reason: reason }, 'Unhandled Rejection'); process.exit(1); }); /** * Lager singleton definition * * The instance will register plugins and emit events * It is an Pebo event emitter */ class Lager extends Pebo { /** * Construct the lager instance * * The lager instance is a singleton that can explore the application configuration * give information about it, control it's validity and perform deployment * * It is possible to register plugins on the lager instance * A lager plugin can implements hooks to inject code and modify the behavior of * the lager instance * A lager plugin can create his own hooks for the lager instance, so it is possible * to create plugins for a lager plugin! * @constructor */ constructor() { super(); this.log = log; this.config = []; this.plugins = []; this.extensions = []; const originalFire = this.fire; // Overide Pebo.fire() to log calls this.fire = function() { const nbListeners = this.events[arguments[0]] ? this.eventslength : 0; this.log.trace('Event ' + arguments[0] + ' has been fired for ' + nbListeners + ' listeners'); return originalFire.apply(this, arguments); }.bind(this); } /** * Add a plugin to the lager instance * @param {Object} plugin * @returns {Lager} */ registerPlugin(plugin) { // We inject the Lager instnce into the plugin plugin.lager = this; // We retrieve the configuration defined in the project for this plugin // The norm in Lager is to write configuration object keys in camelCase const plugiConfigKey = _.camelCase(plugin.name); const pluginConfig = this.getConfig(plugiConfigKey); if (pluginConfig !== undefined) { // We override the default configuration of the plugin with th one of the project plugin.config = _.assign(plugin.config, pluginConfig); } // We reference the "final" plugin configuration in the Lager configuration this.config[plugiConfigKey] = plugin.config; // We "register" the plugin in the Lager instance this.plugins.push(plugin); // Add hooks/event listeners plugin.hooks = plugin.hooks || []; _.map(plugin.hooks, (fn, event) => { this.when(event, fn); }); // Add extensions: functions that extends the Lager instance plugin.extensions = plugin.extensions || []; _.map(plugin.extensions, (fn, extensionName) => { this.extensions[plugin.name + ':' + extensionName] = fn; }); return this; } /** * Check if a plugin is registered * @param {string} name * @returns {boolean} */ isPluginRegistered(name) { return _.findIndex(this.plugins, plugin => { return plugin.name === name;}) !== -1; } /** * Retrieve a plugin by name * @param {string} name * @returns {Object} */ getPlugin(name) { const plugin = _.find(this.plugins, plugin => { return plugin.name === name; }); if (!plugin) { throw new Error('The plugin "' + name + '" is not registered in the Lager instance'); } return plugin; } getVersions() { const versions = this.plugins.map(p => { return { name: p.name, version: p.version || 'unknown'}; }); versions.unshift({ name: 'core', version: require('../../package.json').version}); return versions; } /** * Call an extension * In case the extension has not been added to the Lager instance, * A Promise of the last argument will be returned * @return {Promise} */ call() { // Extract arguments and extension name const args = Array.prototype.slice.call(arguments); const name = args.shift(); if (this.extensions[name]) { return this.extensions[name].apply(null, args); } return Promise.resolve(args[args.length - 1]); } /** * Initialisation of the Lager instance * It looks for a configuration file and register plugins * @return {Promise} - a promise that resolves when the initialisation is finished */ init(config) { // Set configuration from lager.json this.config = config.config; config.plugins = config.plugins || []; _.forEach(config.plugins, pluginIdentifier => { let requireArg = pluginIdentifier; try { // Try to load plugins installed in node_modules require.resolve(requireArg); } catch (e) { try { // Try to load project specific plugins requireArg = path.join(process.cwd(), pluginIdentifier); require.resolve(requireArg); } catch (e) { try { // Hack to use symbolink link to the repo for integration tests requireArg = path.join(process.cwd(), 'node_modules', pluginIdentifier); require.resolve(requireArg); } catch (e) { requireArg = false; lager.log.warn('Lager could not find the plugin "' + pluginIdentifier + '"'); } } } if (requireArg) { lager.registerPlugin(require(requireArg), pluginIdentifier); } }); return this.fire('afterInit'); } getConfig(key) { if (key === undefined) { return this.config; } // If the key has the form "my.config.key" // We look for a value in this.config.my.config.key const configParts = key.split('.'); let part = this.config[configParts.shift()]; while (configParts.length > 0) { if (part === undefined) { // If the nested structure does not exist, we return undefined immediately return undefined; } part = part[configParts.shift()]; } return part; } } const lager = new Lager(); module.exports = lager;