Home Reference Source

src/core.js

/*
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */

import {resolveTreeByKey, providerHandler} from './utils.js';
import {EventEmitter} from '@osjs/event-emitter';
import merge from 'deepmerge';
import omitDeep from 'omit-deep';

/**
 * Core
 *
 * @desc Main class for OS.js service providers and bootstrapping.
 */
export class CoreBase extends EventEmitter {

  /**
   * Create core instance
   * @param {Object} defaultConfiguration Default configuration
   * @param {Object} configuration Configuration given
   * @param {Object} options Options
   */
  constructor(defaultConfiguration, configuration, options) {
    super('Core');

    // https://github.com/KyleAMathews/deepmerge#webpack-bug
    const merger = merge.default ? merge.default : merge;
    const omitted = omitDeep(defaultConfiguration, options.omit || []);

    this.logger = console;
    this.configuration = merger(omitted, configuration);
    this.options = options;
    this.booted = false;
    this.started = false;
    this.destroyed = false;
    this.providers = providerHandler(this);
  }

  /**
   * Destroy core instance
   */
  destroy() {
    if (this.destroyed) {
      return false;
    }

    this.booted = false;
    this.destroyed = true;
    this.started = false;

    const promises = this.providers.destroy();

    super.destroy();

    return promises;
  }

  /**
   * Boots up OS.js
   */
  boot() {
    if (this.booted) {
      return Promise.resolve(true);
    }

    this.started = false;
    this.destroyed = false;
    this.booted = true;

    return this.providers.init(true)
      .then(() => true);
  }

  /**
   * Starts all core services
   */
  start() {
    if (this.started) {
      return Promise.resolve(true);
    }

    this.started = true;

    return this.providers.init(false)
      .then(() => true);
  }

  /**
   * Gets a configuration entry by key
   *
   * @param {String} key The key to get the value from
   * @param {*} [defaultValue] If result is undefined, return this instead
   * @see {resolveTreeByKey}
   * @return {*}
   */
  config(key, defaultValue) {
    return key
      ? resolveTreeByKey(this.configuration, key, defaultValue)
      : Object.assign({}, this.configuration);
  }

  /**
   * Register a service provider
   *
   * @param {Class} ref A class reference
   * @param {Object} [options] Options for handling of provider
   * @param {Boolean} [options.before] Load this provider early
   * @param {Object} [options.args] Arguments to send to the constructor
   */
  register(ref, options = {}) {
    this.providers.register(ref, options);
  }

  /**
   * Register a instanciator provider
   *
   * @param {String} name Provider name
   * @param {Function} callback Callback that returns an instance
   */
  instance(name, callback) {
    this.providers.bind(name, false, callback);
  }

  /**
   * Register a singleton provider
   *
   * @param {String} name Provider name
   * @param {Function} callback Callback that returns an instance
   */
  singleton(name, callback) {
    this.providers.bind(name, true, callback);
  }

  /**
   * Create an instance of a provided service
   *
   * @param {String} name Service name
   * @param {*} args Constructor arguments
   * @return {*} An instance of a service
   */
  make(name, ...args) {
    return this.providers.make(name, ...args);
  }

  /**
   * Check if a service exists
   * @param {String} name Provider name
   * @return {Boolean}
   */
  has(name) {
    return this.providers.has(name);
  }
}