omelop
Version:
[](https://travis-ci.org/node-omelop/omelop)
236 lines • 16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.manualReloadProxies = exports.ProxyComponent = void 0;
/**
* Component for proxy.
* Generate proxies for rpc client.
*/
const crc = require("crc");
const utils = require("../util/utils");
const events_1 = require("../util/events");
const omelop_rpc_1 = require("omelop-rpc");
const Constants = require("../util/constants");
const omelop_logger_1 = require("omelop-logger");
const path = require("path");
let logger = (0, omelop_logger_1.getLogger)('omelop', path.basename(__filename));
/**
* Proxy component class
*
* @param {Object} app current application context
* @param {Object} opts construct parameters
*/
class ProxyComponent {
constructor(app, opts) {
var _a, _b;
this.name = '__proxy__';
opts = opts || {};
// proxy default config
// cacheMsg is deprecated, just for compatibility here.
opts.bufferMsg = opts.bufferMsg || opts.cacheMsg || false;
opts.interval = opts.interval || 30;
opts.router = genRouteFun();
opts.context = (_a = opts.context) !== null && _a !== void 0 ? _a : app;
opts.routeContext = (_b = opts.routeContext) !== null && _b !== void 0 ? _b : app;
if (app.enabled('rpcDebugLog')) {
opts.rpcDebugLog = true;
opts.rpcLogger = (0, omelop_logger_1.getLogger)('rpc-debug', path.basename(__filename));
}
this.app = app;
this.opts = opts;
this.client = genRpcClient(this.app, opts);
this.app.event.on(events_1.default.ADD_SERVERS, this.addServers.bind(this));
this.app.event.on(events_1.default.REMOVE_SERVERS, this.removeServers.bind(this));
this.app.event.on(events_1.default.REPLACE_SERVERS, this.replaceServers.bind(this));
}
/**
* Proxy component lifecycle function
*
* @param {Function} cb
* @return {Void}
*/
start(cb) {
if (this.opts.enableRpcLog) {
logger.warn('enableRpcLog is deprecated in 0.8.0, please use app.rpcFilter(omelop.rpcFilters.rpcLog())');
}
let rpcBefores = this.app.get(Constants.KEYWORDS.RPC_BEFORE_FILTER);
let rpcAfters = this.app.get(Constants.KEYWORDS.RPC_AFTER_FILTER);
let rpcErrorHandler = this.app.get(Constants.RESERVED.RPC_ERROR_HANDLER);
if (!!rpcBefores) {
this.client.before(rpcBefores);
}
if (!!rpcAfters) {
this.client.after(rpcAfters);
}
if (!!rpcErrorHandler) {
this.client.setErrorHandler(rpcErrorHandler);
}
process.nextTick(cb);
}
/**
* Component lifecycle callback
*
* @param {Function} cb
* @return {Void}
*/
afterStart(cb) {
let self = this;
Object.defineProperty(this.app, 'rpc', {
get: function () {
return self.client.proxies.user;
}
});
Object.defineProperty(this.app, 'sysrpc', {
get: function () {
return self.client.proxies.sys;
}
});
this.app.rpcInvoke = this.client.rpcInvoke.bind(this.client);
this.client.start(cb);
}
/**
* Add remote server to the rpc client.
*
* @param {Array} servers server info list, {id, serverType, host, port}
*/
addServers(servers) {
if (!servers || !servers.length) {
return;
}
genProxies(this.client, this.app, servers);
this.client.addServers(servers);
}
manualReloadProxies() {
let servers = [];
for (let k in this.client._station.servers) {
servers.push(this.client._station.servers[k]);
}
logger.warn('manualReloadProxies servers:', servers);
genProxies(this.client, this.app, servers);
}
/**
* Remove remote server from the rpc client.
*
* @param {Array} ids server id list
*/
removeServers(ids) {
this.client.removeServers(ids);
}
/**
* Replace remote servers from the rpc client.
*
* @param {Array} ids server id list
*/
replaceServers(servers) {
if (!servers || !servers.length) {
return;
}
// update proxies
this.client.proxies = {};
genProxies(this.client, this.app, servers);
this.client.replaceServers(servers);
}
/**
* Proxy for rpc client rpcInvoke.
*
* @param {String} serverId remote server id
* @param {Object} msg rpc message: {serverType: serverType, service: serviceName, method: methodName, args: arguments}
* @param {Function} cb callback function
*/
rpcInvoke(serverId, msg, cb) {
this.client.rpcInvoke(serverId, msg, cb);
}
}
exports.ProxyComponent = ProxyComponent;
function manualReloadProxies(app) {
if (!app.components.__proxy__) {
return;
}
if (app.components.__proxy__.manualReloadProxies) {
app.components.__proxy__.manualReloadProxies();
}
else {
logger.warn('manualReloadProxies not method');
}
}
exports.manualReloadProxies = manualReloadProxies;
/**
* Generate rpc client
*
* @param {Object} app current application context
* @param {Object} opts contructor parameters for rpc client
* @return {Object} rpc client
*/
let genRpcClient = function (app, opts) {
var _a, _b;
opts.context = (_a = opts.context) !== null && _a !== void 0 ? _a : app;
opts.routeContext = (_b = opts.routeContext) !== null && _b !== void 0 ? _b : app;
if (!!opts.rpcClient) {
return opts.rpcClient.create(opts);
}
else {
return (0, omelop_rpc_1.createClient)(opts);
}
};
/**
* Generate proxy for the server infos.
*
* @param {Object} client rpc client instance
* @param {Object} app application context
* @param {Array} sinfos server info list
*/
let genProxies = function (client, app, sinfos) {
let item;
for (let i = 0, l = sinfos.length; i < l; i++) {
item = sinfos[i];
client.addProxies(getProxyRecords(app, item));
}
};
/**
* Check a server whether has generated proxy before
*
* @param {Object} client rpc client instance
* @param {Object} sinfo server info
* @return {Boolean} true or false
*/
let hasProxy = function (client, sinfo) {
let proxy = client.proxies;
return !!proxy.sys && !!proxy.sys[sinfo.serverType];
};
/**
* Get proxy path for rpc client.
* Iterate all the remote service path and create remote path record.
*
* @param {Object} app current application context
* @param {Object} sinfo server info, format: {id, serverType, host, port}
* @return {Array} remote path record array
*/
let getProxyRecords = function (app, sinfo) {
return sinfo.remoterPaths;
};
let genRouteFun = function () {
return function (session, msg, app, cb) {
let routes = app.get(Constants.KEYWORDS.ROUTE);
if (!routes) {
defaultRoute(session, msg, app, cb);
return;
}
let type = msg.serverType, route = routes[type] || routes['default'];
if (route) {
route(session, msg, app, cb);
}
else {
defaultRoute(session, msg, app, cb);
}
};
};
let defaultRoute = function (session, msg, app, cb) {
let list = app.getServersByType(msg.serverType);
if (!list || !list.length) {
cb(new Error('can not find server info for type:' + msg.serverType));
return;
}
let uid = session ? (session.uid || '') : '';
let index = Math.abs(crc.crc32(uid.toString())) % list.length;
utils.invokeCallback(cb, null, list[index].id);
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvY29tcG9uZW50cy9wcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7O0dBR0c7QUFDSCwyQkFBMkI7QUFDM0IsdUNBQXVDO0FBQ3ZDLDJDQUFtRDtBQUNuRCwyQ0FBcUQ7QUFFckQsK0NBQStDO0FBQy9DLGlEQUEwQztBQU0xQyw2QkFBNkI7QUFFN0IsSUFBSSxNQUFNLEdBQUcsSUFBQSx5QkFBUyxFQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7QUFhNUQ7Ozs7O0dBS0c7QUFDSCxNQUFhLGNBQWM7SUFLdkIsWUFBWSxHQUFnQixFQUFFLElBQTJCOztRQXNCekQsU0FBSSxHQUFHLFdBQVcsQ0FBQztRQXJCZixJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUNsQix1QkFBdUI7UUFDdkIsdURBQXVEO1FBQ3ZELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLEtBQUssQ0FBQztRQUMxRCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7UUFDNUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFBLElBQUksQ0FBQyxPQUFPLG1DQUFJLEdBQUcsQ0FBQztRQUNuQyxJQUFJLENBQUMsWUFBWSxHQUFHLE1BQUEsSUFBSSxDQUFDLFlBQVksbUNBQUksR0FBRyxDQUFDO1FBQzdDLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsRUFBRTtZQUM1QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztZQUN4QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUEseUJBQVMsRUFBQyxXQUFXLEVBQUUsSUFBSSxDQUFDLFFB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