moleculer
Version:
Fast & powerful microservices framework for Node.JS
191 lines (151 loc) • 4.71 kB
JavaScript
/*
* moleculer
* Copyright (c) 2017 Ice Services (https://github.com/ice-services/moleculer)
* MIT Licensed
*/
"use strict";
const isFunction = require("lodash/isFunction");
const forIn = require("lodash/forIn");
const isObject = require("lodash/isObject");
const cloneDeep = require("lodash/cloneDeep");
const utils = require("./utils");
const Promise = require("bluebird");
/**
* Main Service class
*
* @class Service
*/
class Service {
/**
* Creates an instance of Service by schema.
*
* @param {ServiceBroker} broker broker of service
* @param {Object} schema schema of service
*
* @memberOf Service
*/
constructor(broker, schema) {
if (!isObject(broker)) {
throw new Error("Must to set a ServiceBroker instance!");
}
if (!isObject(schema)) {
throw new Error("Must pass a service schema in constructor!");
}
if (schema.mixins) {
schema = Service.applyMixins(schema);
}
if (!schema.name) {
throw new Error("Service name can't be empty!");
}
this.name = schema.name;
this.version = schema.version;
this.settings = schema.settings || {};
this.schema = schema;
this.broker = broker;
if (broker) {
this.Promise = broker.Promise;
}
this.logger = this.broker.getLogger(this.name.toUpperCase() + "-SVC");
this.actions = {}; // external access to actions
this.broker.registerLocalService(this);
// Register actions
if (isObject(schema.actions)) {
forIn(schema.actions, (action, name) => {
if (isFunction(action)) {
// Wrap to an object
action = {
handler: action
};
}
let innerAction = this._createActionHandler(cloneDeep(action), name);
// Register to broker
broker.registerAction(null, innerAction);
// Expose to call `service.actions.find({ ...params })`
this.actions[name] = (params, opts) => {
const ctx = broker.createNewContext(innerAction, null, params, opts);
return innerAction.handler(ctx);
};
});
}
// Event subscriptions
if (isObject(schema.events)) {
forIn(schema.events, (event, name) => {
if (isFunction(event)) {
event = {
handler: event
};
}
if (!event.name)
event.name = event;
if (!isFunction(event.handler)) {
throw new Error(`Missing event handler on '${name}' event in '${this.name}' service!`);
}
const self = this;
const handler = function(payload, sender) {
return event.handler.apply(self, [payload, sender, this.event]);
};
broker.on(name, handler);
});
}
// Register methods
if (isObject(schema.methods)) {
forIn(schema.methods, (method, name) => {
/* istanbul ignore next */
if (["name", "version", "settings", "schema", "broker", "actions", "logger"].indexOf(name) != -1) {
throw new Error(`Invalid method name '${name}' in '${this.name}' service!`);
}
this[name] = method.bind(this);
});
}
// Call `created` function from schema
if (isFunction(this.schema.created)) {
this.schema.created.call(this);
}
}
/**
* Create an external action handler for broker (internal command!)
*
* @param {any} action
* @param {any} name
* @returns
*
* @memberOf Service
*/
_createActionHandler(action, name) {
let handler = action.handler;
if (!isFunction(handler)) {
throw new Error(`Missing action handler on '${name}' action in '${this.name}' service!`);
}
if (this.settings.serviceNamePrefix !== false)
action.name = this.name + "." + (action.name || name);
else
action.name = action.name || name;
if (this.version && this.settings.useVersionPrefix !== false)
action.name = `v${this.version}.${action.name}`;
//action.origName = name;
action.version = this.version;
action.service = this;
action.cache = action.cache !== undefined ? action.cache : (this.settings.cache || false);
action.handler = Promise.method(handler.bind(this));
return action;
}
/**
* Apply `mixins` list in schema. Merge the schema with mixins schemas. Returns with the mixed schema
*
* @static
* @param {Schema} schema
* @returns {Schema}
*
* @memberof Service
*/
static applyMixins(schema) {
if (schema.mixins) {
const mixins = Array.isArray(schema.mixins) ? schema.mixins : [schema.mixins];
const mixedSchema = mixins.reduce((s, mixin) => utils.mergeSchemas(s, mixin), {});
return utils.mergeSchemas(mixedSchema, schema);
}
/* istanbul ignore next */
return schema;
}
}
module.exports = Service;