UNPKG

@sex-pomelo/sex-pomelo

Version:

[![NPM version][npm-image-pomelo]][npm-url-pomelo] [![NPM version][npm-image-down]][npm-url-pomelo]

284 lines (250 loc) 8.01 kB
"use strict"; /** * @file Component for proxy. * Generate proxies for rpc client. */ const utils = require('../util/utils'); const events = require('../util/events'); const Client = require('@sex-pomelo/sex-pomelo-rpc').client; const pathUtil = require('../util/pathUtil'); const Constants = require('../util/constants'); const reFilename = __filename.substring(__filename.indexOf("node_modules")) const logger = require('@sex-pomelo/sex-pomelo-logger').getLogger('pomelo', reFilename); /** * @typedef {import('../application').Application} Application */ /** * Component factory function * * @param {Application} app current application context * @param {Object} opts construct parameters * opts.router: (optional) rpc message route function, route(routeParam, msg, cb), * opts.mailBoxFactory: (optional) mail box factory instance. * @return {Object} component instance */ module.exports = function(app, opts) { 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 = app; opts.routeContext = app; if (app.enabled('rpcDebugLog')) { opts.rpcDebugLog = true; opts.rpcLogger = require('@sex-pomelo/sex-pomelo-logger').getLogger('rpc-debug', reFilename); } return new ComponentProxy(app, opts); }; /** * Proxy component class * @class * @implements {Component} * * @param {Object} app current application context * @param {Object} opts construct parameters */ let ComponentProxy = function(app, opts) { this.app = app; this.opts = opts; this.client = genRpcClient(this.app, opts); this.app.event.on(events.ADD_SERVERS, this.addServers.bind(this)); this.app.event.on(events.REMOVE_SERVERS, this.removeServers.bind(this)); this.app.event.on(events.REPLACE_SERVERS, this.replaceServers.bind(this)); }; ComponentProxy.prototype.name = '__proxy__'; /** * Proxy component lifecycle function * * @param {Function} cb * @return {Void} */ ComponentProxy.prototype.start = function(cb) { if(this.opts.enableRpcLog) { logger.warn('enableRpcLog is deprecated in 0.8.0, please use app.rpcFilter(pomelo.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} */ ComponentProxy.prototype.afterStart = function(cb) { let self = this; // this.app.__defineGetter__('rpc', function() { // return self.client.proxies.user; // }); Object.defineProperty(self.app, 'rpc', {enumerable: true, get: function(){ return self.client.proxies.user}, }); // this.app.__defineGetter__('sysrpc', function() { // return self.client.proxies.sys; // }); Object.defineProperty(self.app, 'sysrpc', {enumerable: true, get: function(){ return self.client.proxies.sys}, }); this.app.set('rpcInvoke', this.client.rpcInvoke.bind(this.client), true); this.client.start(cb); }; /** * Add remote server to the rpc client. * * @param {Array} servers server info list, {id, serverType, host, port} */ ComponentProxy.prototype.addServers = function(servers) { if (!servers || !servers.length) { return; } genProxies(this.client, this.app, servers); this.client.addServers(servers); }; /** * Remove remote server from the rpc client. * * @param {Array} ids server id list */ ComponentProxy.prototype.removeServers = function(ids) { this.client.removeServers(ids); }; /** * Replace remote servers from the rpc client. * * @param {Array} ids server id list */ ComponentProxy.prototype.replaceServers = function(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 */ ComponentProxy.prototype.rpcInvoke = function(serverId, msg, cb) { this.client.rpcInvoke(serverId, msg, cb); }; /** * Generate rpc client * @access private * @param {Object} app current application context * @param {Object} opts contructor parameters for rpc client * @return {Object} rpc client */ let genRpcClient = function(app, opts) { opts.context = app; opts.routeContext = app; if(!!opts.rpcClient) { return opts.rpcClient.create(opts); } else { return Client.create(opts); } }; /** * Generate proxy for the server infos. * @access private * @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]; if (hasProxy(client, item)) { continue; } client.addProxies(getProxyRecords(app, item)); } }; /** * Check a server whether has generated proxy before * @access private * @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. * @access private * @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) { let records = [], appBase = app.getBase(), record; // sys remote service path record if (app.isFrontend(sinfo)) { record = pathUtil.getSysRemotePath('frontend'); } else { record = pathUtil.getSysRemotePath('backend'); } if (record) { records.push(pathUtil.remotePathRecord('sys', sinfo.serverType, record)); } // user remote service path record record = pathUtil.getUserRemotePath(appBase, sinfo.serverType); if (record) { records.push(pathUtil.remotePathRecord('user', sinfo.serverType, record)); } return records; }; let genRouteFun = function() { return function(session, msg, app, cb) { let routes = app.get('__routes__'); 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 = 0; if( typeof(uid) === 'number' ){ index = Math.abs(uid) % list.length; }else{ index = Math.floor(Math.random()*100000) % list.length; } utils.invokeCallback(cb, null, list[index].id); };