proxy.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /**
  2. * Component for proxy.
  3. * Generate proxies for rpc client.
  4. */
  5. var crc = require('crc');
  6. var utils = require('../util/utils');
  7. var events = require('../util/events');
  8. var Client = require('pomelo-rpc').client;
  9. var pathUtil = require('../util/pathUtil');
  10. var Constants = require('../util/constants');
  11. var logger = require('pomelo-logger').getLogger('pomelo', __filename);
  12. /**
  13. * Component factory function
  14. *
  15. * @param {Object} app current application context
  16. * @param {Object} opts construct parameters
  17. * opts.router: (optional) rpc message route function, route(routeParam, msg, cb),
  18. * opts.mailBoxFactory: (optional) mail box factory instance.
  19. * @return {Object} component instance
  20. */
  21. module.exports = function(app, opts) {
  22. opts = opts || {};
  23. // proxy default config
  24. // cacheMsg is deprecated, just for compatibility here.
  25. opts.bufferMsg = opts.bufferMsg || opts.cacheMsg || false;
  26. opts.interval = opts.interval || 30;
  27. opts.router = genRouteFun();
  28. opts.context = app;
  29. opts.routeContext = app;
  30. if (app.enabled('rpcDebugLog')) {
  31. opts.rpcDebugLog = true;
  32. opts.rpcLogger = require('pomelo-logger').getLogger('rpc-debug', __filename);
  33. }
  34. return new Component(app, opts);
  35. };
  36. /**
  37. * Proxy component class
  38. *
  39. * @param {Object} app current application context
  40. * @param {Object} opts construct parameters
  41. */
  42. var Component = function(app, opts) {
  43. this.app = app;
  44. this.opts = opts;
  45. this.client = genRpcClient(this.app, opts);
  46. this.app.event.on(events.ADD_SERVERS, this.addServers.bind(this));
  47. this.app.event.on(events.REMOVE_SERVERS, this.removeServers.bind(this));
  48. this.app.event.on(events.REPLACE_SERVERS, this.replaceServers.bind(this));
  49. };
  50. var pro = Component.prototype;
  51. pro.name = '__proxy__';
  52. /**
  53. * Proxy component lifecycle function
  54. *
  55. * @param {Function} cb
  56. * @return {Void}
  57. */
  58. pro.start = function(cb) {
  59. if(this.opts.enableRpcLog) {
  60. logger.warn('enableRpcLog is deprecated in 0.8.0, please use app.rpcFilter(pomelo.rpcFilters.rpcLog())');
  61. }
  62. var rpcBefores = this.app.get(Constants.KEYWORDS.RPC_BEFORE_FILTER);
  63. var rpcAfters = this.app.get(Constants.KEYWORDS.RPC_AFTER_FILTER);
  64. var rpcErrorHandler = this.app.get(Constants.RESERVED.RPC_ERROR_HANDLER);
  65. if(!!rpcBefores) {
  66. this.client.before(rpcBefores);
  67. }
  68. if(!!rpcAfters) {
  69. this.client.after(rpcAfters);
  70. }
  71. if(!!rpcErrorHandler) {
  72. this.client.setErrorHandler(rpcErrorHandler);
  73. }
  74. process.nextTick(cb);
  75. };
  76. /**
  77. * Component lifecycle callback
  78. *
  79. * @param {Function} cb
  80. * @return {Void}
  81. */
  82. pro.afterStart = function(cb) {
  83. var self = this;
  84. this.app.__defineGetter__('rpc', function() {
  85. return self.client.proxies.user;
  86. });
  87. this.app.__defineGetter__('sysrpc', function() {
  88. return self.client.proxies.sys;
  89. });
  90. this.app.set('rpcInvoke', this.client.rpcInvoke.bind(this.client), true);
  91. this.client.start(cb);
  92. };
  93. /**
  94. * Add remote server to the rpc client.
  95. *
  96. * @param {Array} servers server info list, {id, serverType, host, port}
  97. */
  98. pro.addServers = function(servers) {
  99. if (!servers || !servers.length) {
  100. return;
  101. }
  102. genProxies(this.client, this.app, servers);
  103. this.client.addServers(servers);
  104. };
  105. /**
  106. * Remove remote server from the rpc client.
  107. *
  108. * @param {Array} ids server id list
  109. */
  110. pro.removeServers = function(ids) {
  111. this.client.removeServers(ids);
  112. };
  113. /**
  114. * Replace remote servers from the rpc client.
  115. *
  116. * @param {Array} ids server id list
  117. */
  118. pro.replaceServers = function(servers) {
  119. if (!servers || !servers.length) {
  120. return;
  121. }
  122. // update proxies
  123. this.client.proxies = {};
  124. genProxies(this.client, this.app, servers);
  125. this.client.replaceServers(servers);
  126. };
  127. /**
  128. * Proxy for rpc client rpcInvoke.
  129. *
  130. * @param {String} serverId remote server id
  131. * @param {Object} msg rpc message: {serverType: serverType, service: serviceName, method: methodName, args: arguments}
  132. * @param {Function} cb callback function
  133. */
  134. pro.rpcInvoke = function(serverId, msg, cb) {
  135. this.client.rpcInvoke(serverId, msg, cb);
  136. };
  137. /**
  138. * Generate rpc client
  139. *
  140. * @param {Object} app current application context
  141. * @param {Object} opts contructor parameters for rpc client
  142. * @return {Object} rpc client
  143. */
  144. var genRpcClient = function(app, opts) {
  145. opts.context = app;
  146. opts.routeContext = app;
  147. if(!!opts.rpcClient) {
  148. return opts.rpcClient.create(opts);
  149. } else {
  150. return Client.create(opts);
  151. }
  152. };
  153. /**
  154. * Generate proxy for the server infos.
  155. *
  156. * @param {Object} client rpc client instance
  157. * @param {Object} app application context
  158. * @param {Array} sinfos server info list
  159. */
  160. var genProxies = function(client, app, sinfos) {
  161. var item;
  162. for (var i = 0, l = sinfos.length; i < l; i++) {
  163. item = sinfos[i];
  164. if (hasProxy(client, item)) {
  165. continue;
  166. }
  167. client.addProxies(getProxyRecords(app, item));
  168. }
  169. };
  170. /**
  171. * Check a server whether has generated proxy before
  172. *
  173. * @param {Object} client rpc client instance
  174. * @param {Object} sinfo server info
  175. * @return {Boolean} true or false
  176. */
  177. var hasProxy = function(client, sinfo) {
  178. var proxy = client.proxies;
  179. return !!proxy.sys && !! proxy.sys[sinfo.serverType];
  180. };
  181. /**
  182. * Get proxy path for rpc client.
  183. * Iterate all the remote service path and create remote path record.
  184. *
  185. * @param {Object} app current application context
  186. * @param {Object} sinfo server info, format: {id, serverType, host, port}
  187. * @return {Array} remote path record array
  188. */
  189. var getProxyRecords = function(app, sinfo) {
  190. var records = [],
  191. appBase = app.getBase(),
  192. record;
  193. // sys remote service path record
  194. if (app.isFrontend(sinfo)) {
  195. record = pathUtil.getSysRemotePath('frontend');
  196. } else {
  197. record = pathUtil.getSysRemotePath('backend');
  198. }
  199. if (record) {
  200. records.push(pathUtil.remotePathRecord('sys', sinfo.serverType, record));
  201. }
  202. // userstate remote service path record
  203. record = pathUtil.getUserRemotePath(appBase, sinfo.serverType);
  204. if (record) {
  205. records.push(pathUtil.remotePathRecord('user', sinfo.serverType, record));
  206. }
  207. return records;
  208. };
  209. var genRouteFun = function() {
  210. return function(session, msg, app, cb) {
  211. var routes = app.get('__routes__');
  212. if (!routes) {
  213. defaultRoute(session, msg, app, cb);
  214. return;
  215. }
  216. var type = msg.serverType,
  217. route = routes[type] || routes['default'];
  218. if (route) {
  219. route(session, msg, app, cb);
  220. } else {
  221. defaultRoute(session, msg, app, cb);
  222. }
  223. };
  224. };
  225. var defaultRoute = function(session, msg, app, cb) {
  226. var list = app.getServersByType(msg.serverType);
  227. if (!list || !list.length) {
  228. cb(new Error('can not find server info for type:' + msg.serverType));
  229. return;
  230. }
  231. var uid = session ? (session.uid || '') : '';
  232. var index = Math.abs(crc.crc32(uid.toString())) % list.length;
  233. utils.invokeCallback(cb, null, list[index].id);
  234. };