Home Reference Source

packages/skygear-core/lib/cloud/registry.js

/**
 * Copyright 2015 Oursky Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* eslint-disable no-var, camelcase */
import _ from 'lodash';
import { createLogger } from './logging';

export class Registry {
  constructor() {
    this.funcMap = {
      op: {},
      event: {},
      hook: {},
      timer: {}
    };
    this.paramMap = {
      op: [],
      event: [],
      handler: [],
      hook: [],
      timer: [],
      provider: []
    };
    this.handlers = {};
    this.providers = {};
    this._hookTypeMap = {};
    this.staticAsset = {};
  }

  _addParamHandler(param) {
    const logger = createLogger('plugin').child({tag: 'plugin'});

    const kind = 'handler';
    let list = this.paramMap[kind];
    list = list.filter(function (item) {
      if (
        item.name === param.name &&
        !_.isEmpty(_.intersection(item.methods, param.methods))
      ) {
        logger.warn(`Replacing previously registered ${kind}: ${item.name}`);
        return false;
      }
      return true;
    });
    _.forEach(param.methods, function (method) {
      const newParam = _.cloneDeep(param);
      newParam.methods = [method];
      list.push(newParam);
    });
    this.paramMap[kind] = list;
  }

  _addParam(kind, param) {
    if (kind === 'handler') {
      return this._addParamHandler(param);
    }

    const logger = createLogger('plugin').child({tag: 'plugin'});

    let list = this.paramMap[kind];
    list = list.filter(function (item) {
      if (item.name === param.name) {
        logger.warn(`Replacing previously registered ${kind}: ${item.name}`);
        return false;
      }
      return true;
    });
    list.push(param);
    this.paramMap[kind] = list;
  }

  registerHook(name, func, options) {
    if (!options.type) {
      throw new Error('type is required for hook');
    }
    if (!options.trigger) {
      throw new Error('trigger is required for hook');
    }
    const opts = {
      ...options,
      name: name
    };
    this._addParam('hook', opts);
    this.funcMap.hook[name] = func;
    this._hookTypeMap[name] = options.type;
  }

  registerOp(name, func, options) {
    const opts = {
      name: name,
      key_required: options.keyRequired,
      user_required: options.userRequired
    };
    this._addParam('op', opts);
    this.funcMap.op[name] = func;
  }

  registerEvent(name, func) {
    const eventParams = this.paramMap.event.filter((e) => e.name === name);
    if (eventParams.length === 0) {
      this._addParam('event', { name });
    }

    const funcList = this.funcMap.event[name] || [];
    funcList.push(func);

    this.funcMap.event[name] = funcList;
  }

  registerTimer(name, func, options) {
    const opts = {
      ...options,
      name: name
    };
    this._addParam('timer', opts);
    this.funcMap.timer[name] = func;
  }

  registerHandler(name, func, options) {
    const m = options.method || ['GET', 'POST', 'PUT'];
    const opts = {
      name: name,
      methods: m,
      key_required: options.keyRequired,
      user_required: options.userRequired
    };
    this._addParam('handler', opts);
    if (!this.handlers[name]) {
      this.handlers[name] = {};
    }
    m.forEach((_m) => {
      this.handlers[name][_m] = func;
    });
  }

  registerProvider(providerType, providerID, provider, options) {
    const opts = {
      ...options,
      type: providerType,
      id: providerID
    };
    this._addParam('provider', opts);
    this.providers[providerID] = provider;
  }

  registerAsset(path, func) {
    this.staticAsset[path] = func;
  }

  getFunc(kind, name) {
    if (kind === 'event') {
      throw new Error('getFunc() is not compatible with event kind');
    }
    return this.funcMap[kind][name];
  }

  getEventFunctions(name) {
    return this.funcMap.event[name];
  }

  getHookType(name) {
    return this._hookTypeMap[name];
  }

  getHandler(name, method) {
    return this.handlers[name][method];
  }

  getProvider(name) {
    return this.providers[name];
  }

  funcList() {
    return this.paramMap;
  }
}

const registry = new Registry();
export default registry;