src/model/server.js

'use strict';

const Hapi = require('hapi');
const merge = require('lodash/merge');
const logger = require('../logger');
const {HOOKS:{CONF, LOG_STREAM, ENV}} = require('../addon/index');
const Promise = require('bluebird');
const FlamingoOperation = require('./flamingo-operation');
const Route = require('./route');
const assert = require('assert');

/**
 * Flamingo server
 * @class
 * @property {Config} config server config
 * @property {AddonLoader} addonsLoader addon loader
 * @property {Object} hapi hapi server instance
 */
class Server {
  /**
   * Takes a config and an addon loader to build the server.
   * @constructor
   * @param {Config} config
   * @param {AddonLoader} addonsLoader
   */
  constructor(config, addonsLoader) {
    this.config = config;
    FlamingoOperation.prototype.config = this.config;
    this.addonsLoader = addonsLoader;

    this.addonsLoader.hook(CONF)(this.config);
    this.addonsLoader.hook(ENV)(this.config, process.env);
    this.addonsLoader.hook(LOG_STREAM, this.config)(logger, this.config);

    this.profiles = {};

    this.hapi = new Hapi.Server({
      debug: this.config.DEBUG ? {log: ['error'], request: ['error']} : false
    });
    this.hapi.connection({
      port: this.config.PORT,
      host: this.config.HOST
    });
  }

  /**
   * Add the given routes to the server instance
   * @param {Array.<Route>} routes routes to add to the server instance
   * @returns {Server}
   */
  withRoutes(routes) {
    routes.forEach((route) => {
      assert.ok(route instanceof Route);
      route.server = this;
      this.hapi.route(route.hapiConfig());
    });
    return this;
  }

  /**
   * Add the given profiles to the server instance
   * @param {Array.<{}>} profiles profiles to add to the server instance
   * @returns {Server}
   */
  withProfiles(profiles) {
    profiles.forEach(profile =>
      merge(this.profiles, profile));
    return this;
  }

  /**
   * Stop the server instance
   * @return {Promise.<Server>}
   */
  stop() {
    return new Promise((resolve, reject) => {
      this.hapi.stop((err) => {
        /* istanbul ignore next */
        if (err) reject(err);
        else resolve(this);
      });
    });
  }

  /**
   * Starts the server instance
   * @return {Promise.<Server>}
   */
  start() {
    return new Promise((resolve, reject) => {
      this.hapi.start((err, data) => {
        /* istanbul ignore next */
        if (err) reject(err);
        else resolve(this);
      });
    });
  }
}

module.exports = Server;