lib/remoteServiceManager.js
const _ = require('lodash');
module.exports = RemoteServiceManager;
module.exports.RemoteServiceManager = RemoteServiceManager;
/**
* A factory for `BIServiceSDK` instances
* (see affiliated [bi-service-sdk](https://github.com/BohemiaInteractive/bi-service-sdk) plugin)
* and {@tutorial 4.SDK-integration}
*
* @param {Object} services
* @param {Object} services.<serviceName> - index name = name of the service
* @param {Object} services.<serviceName>.<scope> - index name not constrained, could be anything... eg.: specific service application name (in case multiple applications are listening under one service) or access level type eg.: "public" or "s2s"
* @param {String} services.<serviceName>.<scope>.npm - npm package name which exports object that inherits BIServiceSDK
* @param {String} services.<serviceName>.<scope>.host
* @param {Boolean} services.<serviceName>.<scope>.ssl
*
* @constructor
*/
function RemoteServiceManager(services) {
this.options = services || {};
this.services = {};
/**
* `BIServiceSDK` constructor
* @name RemoteServiceManager#BIServiceSDK
* @instance
* @type {Function}
*/
let sdk = require('bi-service-sdk');
// sdk.BIServiceSDK interface is depracated and sdk.BIServiceSDKInterface
// should be used instead
this.BIServiceSDK = sdk.BIServiceSDKInterface || sdk.BIServiceSDK;
}
/**
* registers `BIServiceSDK` instance
*
* @public
* @param {String} key - format `<serviceName>:<scope>`
* @param {BIServiceSDK} sdk
*
* @return {RemoteServiceManager} - self
*/
RemoteServiceManager.prototype.add = function(key, sdk) {
let keySegments = key.split(':');
if (!(sdk instanceof this.BIServiceSDK)) {
throw new Error('sdk must be instanceof BIServiceSDK');
}
if (keySegments.length < 2) {
throw new Error('The first argument must be in format: `<serviceName>:<scope>`');
}
_.set(this.services, keySegments.concat([sdk.version]), sdk);
return this;
};
/**
* @public
* @param {String} key - format `<serviceName>:<scope>:<version>`
*
* @return {BIServiceSDK}
*/
RemoteServiceManager.prototype.get = function(key) {
let remoteService = _.get(this.services, key.split(':'));
if (!(remoteService instanceof this.BIServiceSDK)) {
throw new Error(`${key} remote service not found`);
}
return remoteService;
};
/**
* @public
* @param {String} key - format `<serviceName>:<scope>:<version>` (scope|version key segments are optional)
*
* @return {Boolean}
*/
RemoteServiceManager.prototype.has = function(key) {
let segments = key.split(':');
if (segments.length > 3) {
throw new Error(`${key} should be in format: <serviceName>:<scope>:<version>`);
}
return _.has(this.services, key.split(':'));
};
/**
* constructs specific `BIServiceSDK` from configuration provided to the constructor
* the specific `BIServiceSDK` is supposed to be auto generated by `bi-service-sdk` plugin
* and published as a npm package
*
* @example
* //config.json5:
* {
* services: {
* user: {
* public: {
* ssl: true,
* host: "127.0.0.1:4001",
* npm: "bi-user-public-sdk"
* }
* }
* }
* }
*
* //method usage
* remoteServiceManager.buildRemoteService('user:public:v1.0');
*
* @public
*
* @param {String} key - format: `<serviceName>:<scope>:<version>`
* @param {Object} [options] - `BIServiceSDK` constructor options
*
* @throws {Error}
* @return {BIServiceSDK}
*/
RemoteServiceManager.prototype.buildRemoteService = function(key, options) {
let keySegments = key.split(':');
let serviceName = keySegments[0];
let scope = keySegments[1];
let sdkPath = keySegments.slice(2);
let version = sdkPath.pop();
if (keySegments.length < 3) {
throw new Error('The first argument must be in format: `<serviceName>:<scope>:<version>`');
}
let confPath = `${serviceName}:${scope}`;
let conf = _.get(this.options, [serviceName, scope]);
if (!conf) {
throw new Error(`Cant find config value of "${confPath}"`);
}
if (!_.isPlainObject(conf) || !conf.npm) {
throw new Error(`"services:${confPath}:npm" config option not found. Cant connect remote service.`);
}
let sdkVersions = module.require(conf.npm);
let sdkContructorPath = sdkPath.concat([version]);
let sdkContructor = _.get(sdkVersions, sdkContructorPath);
if (!sdkContructor) {
throw new Error(`${confPath} service sdk does not have version: ${sdkContructorPath}`);
}
let opt =_.omit(conf, 'protocol', 'ssl', 'host', 'npm');
Object.assign(opt, options || {});
let protocol = conf.protocol || (conf.ssl ? 'https' : 'http');
if (conf.host) {
opt.baseURL = protocol + '://' + conf.host;
}
let sdk = new sdkContructor(opt);
this.add(
`${serviceName}:${scope}${sdkPath.length ? ':' + sdkPath.join(':') : ''}`,
sdk
);
return sdk;
};