UNPKG

waigo

Version:

Node.js ES6 framework for reactive, data-driven apps and APIs (Koa, RethinkDB)

200 lines (142 loc) 3.82 kB
"use strict"; /** * @file * The Waigo application object. */ const debug = require('debug')('waigo_application'), koa = require('koa'), log4js = require('log4js'), EventEmitter = require('eventemitter3'), path = require('path'); const waigo = global.waigo, _ = waigo._, logger = waigo.load('support/logger'), errors = waigo.load('support/errors'); // underscore mixins waigo.load('support/lodashMixins')(_); const AppError = errors.define('AppError'); /** * The application object. * * This is the main entry point for all Waigo applications. It is responsible * for constructing the Koa `app` object, loading in the app * configuration, initialising logging and running all startup steps. */ class Application extends EventEmitter { constructor () { super(); this._initKoa(); this._onError = this._onError.bind(this); } /** * Initialize koa. * * @protected */ _initKoa () { var self = this; this.koa = koa(); /** * Default middleware! */ this.koa.use(function*(next) { this.App = self; yield next; }); } /** * Load in the application configuration. * * This gets called automatically during startup. * * @param {Object} [options] Additional options. * @param {Function} [options.postConfig] Function to pass configuration object to once loaded. * Should have signature `function (config: Object)`. * * @protected */ * _loadConfig (options) { options = options || {}; debug('Loading configuration'); this.config = waigo.load('config/index')(); if (options.postConfig) { debug('Executing dynamic configuration'); options.postConfig.call(null, this.config); } } /** * Handle an error. * * @param {Error} err The error. * * @protected */ _onError (err) { this.logger.error(err.stack ? err.stack : err); }; /** * Setup application logger. * * Upon completion `this.logger` will be set. * * @param {Object} cfg Logger configuration. * * @see support/logger.js * @protected */ * _setupLogger (cfg) { debug('Setup logging'); this.logger = logger.init(cfg); process.on('uncaughtException', this._onError); this.koa.on('error', this._onError); this.on('error', this._onError); } /** * Start the application. * * @param {Object} [options] Additional options. * @param {Function} [options.postConfig] Function to pass configuration object to once loaded. * Should have signature `function (config: Object)`. */ * start (options) { if (this.config) { throw new AppError('Application already started'); } // load config yield this._loadConfig(options); // logging yield this._setupLogger(this.config.logging); for (let stepName of this.config.startupSteps) { this.logger.debug(`Running startup step: ${stepName}`); /*jshint -W030 */ yield waigo.load(`support/startup/${stepName}`)(this); } this.logger.info('Startup complete'); } /** * Stop the application. * * This will reset the internal Koa `app` object. */ * shutdown () { if (!this.config) { throw new AppError('Application not started'); } // remove uncaught exception handler process.removeListener('uncaughtException', this._onError); // run shutdown steps for (let stepName of this.config.shutdownSteps) { this.logger.debug(`Running shutdown step: ${stepName}`); /*jshint -W030 */ yield waigo.load(`support/shutdown/${stepName}`)(this); } this.logger.info('Shutdown complete'); delete this.config; // reset koa this._initKoa(); }; } /** * @type {Class} */ module.exports = Application;