application.js 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. /*!
  2. * Pomelo -- proto
  3. * Copyright(c) 2012 xiechengchao <xiecc@163.com>
  4. * MIT Licensed
  5. */
  6. /**
  7. * Module dependencies.
  8. */
  9. var utils = require('./util/utils');
  10. var logger = require('pomelo-logger').getLogger('pomelo', __filename);
  11. var EventEmitter = require('events').EventEmitter;
  12. var events = require('./util/events');
  13. var appUtil = require('./util/appUtil');
  14. var Constants = require('./util/constants');
  15. var appManager = require('./common/manager/appManager');
  16. var fs = require('fs');
  17. var path = require('path');
  18. /**
  19. * Application prototype.
  20. *
  21. * @module
  22. */
  23. var Application = module.exports = {};
  24. /**
  25. * Application states
  26. */
  27. var STATE_INITED = 1; // app has inited
  28. var STATE_START = 2; // app start
  29. var STATE_STARTED = 3; // app has started
  30. var STATE_STOPED = 4; // app has stoped
  31. /**
  32. * Initialize the server.
  33. *
  34. * - setup default configuration
  35. */
  36. Application.init = function(opts) {
  37. opts = opts || {};
  38. this.loaded = []; // loaded component list
  39. this.components = {}; // name -> component map
  40. this.settings = {}; // collection keep set/get
  41. var base = opts.base || path.dirname(require.main.filename);
  42. this.set(Constants.RESERVED.BASE, base, true);
  43. this.event = new EventEmitter(); // event object to sub/pub events
  44. // current server info
  45. this.serverId = null; // current server id
  46. this.serverType = null; // current server type
  47. this.curServer = null; // current server info
  48. this.startTime = null; // current server start time
  49. // global server infos
  50. this.master = null; // master server info
  51. this.servers = {}; // current global server info maps, id -> info
  52. this.serverTypeMaps = {}; // current global type maps, type -> [info]
  53. this.serverTypes = []; // current global server type list
  54. this.lifecycleCbs = {}; // current server custom lifecycle callbacks
  55. this.clusterSeq = {}; // cluster id seqence
  56. appUtil.defaultConfiguration(this);
  57. this.state = STATE_INITED;
  58. logger.info('application inited: %j', this.getServerId());
  59. };
  60. /**
  61. * Get application base path
  62. *
  63. * // cwd: /home/game/
  64. * pomelo start
  65. * // app.getBase() -> /home/game
  66. *
  67. * @return {String} application base path
  68. *
  69. * @memberOf Application
  70. */
  71. Application.getBase = function() {
  72. return this.get(Constants.RESERVED.BASE);
  73. };
  74. /**
  75. * Override require method in application
  76. *
  77. * @param {String} relative path of file
  78. *
  79. * @memberOf Application
  80. */
  81. Application.require = function(ph) {
  82. return require(path.join(Application.getBase(), ph));
  83. };
  84. /**
  85. * Configure logger with {$base}/config/log4js.json
  86. *
  87. * @param {Object} logger pomelo-logger instance without configuration
  88. *
  89. * @memberOf Application
  90. */
  91. Application.configureLogger = function(logger) {
  92. if (process.env.POMELO_LOGGER !== 'off') {
  93. var base = this.getBase();
  94. var env = this.get(Constants.RESERVED.ENV);
  95. var originPath = path.join(base, Constants.FILEPATH.LOG);
  96. var presentPath = path.join(base, Constants.FILEPATH.CONFIG_DIR, env, path.basename(Constants.FILEPATH.LOG));
  97. if(fs.existsSync(originPath)) {
  98. logger.configure(originPath, {serverId: this.serverId, base: base});
  99. } else if(fs.existsSync(presentPath)) {
  100. logger.configure(presentPath, {serverId: this.serverId, base: base});
  101. } else {
  102. logger.error('logger file path configuration is error.');
  103. }
  104. }
  105. };
  106. /**
  107. * add a filter to before and after filter
  108. *
  109. * @param {Object} filter provide before and after filter method.
  110. * A filter should have two methods: before and after.
  111. * @memberOf Application
  112. */
  113. Application.filter = function (filter) {
  114. this.before(filter);
  115. this.after(filter);
  116. };
  117. /**
  118. * Add before filter.
  119. *
  120. * @param {Object|Function} bf before fileter, bf(msg, session, next)
  121. * @memberOf Application
  122. */
  123. Application.before = function (bf) {
  124. addFilter(this, Constants.KEYWORDS.BEFORE_FILTER, bf);
  125. };
  126. /**
  127. * Add after filter.
  128. *
  129. * @param {Object|Function} af after filter, `af(err, msg, session, resp, next)`
  130. * @memberOf Application
  131. */
  132. Application.after = function (af) {
  133. addFilter(this, Constants.KEYWORDS.AFTER_FILTER, af);
  134. };
  135. /**
  136. * add a global filter to before and after global filter
  137. *
  138. * @param {Object} filter provide before and after filter method.
  139. * A filter should have two methods: before and after.
  140. * @memberOf Application
  141. */
  142. Application.globalFilter = function (filter) {
  143. this.globalBefore(filter);
  144. this.globalAfter(filter);
  145. };
  146. /**
  147. * Add global before filter.
  148. *
  149. * @param {Object|Function} bf before fileter, bf(msg, session, next)
  150. * @memberOf Application
  151. */
  152. Application.globalBefore = function (bf) {
  153. addFilter(this, Constants.KEYWORDS.GLOBAL_BEFORE_FILTER, bf);
  154. };
  155. /**
  156. * Add global after filter.
  157. *
  158. * @param {Object|Function} af after filter, `af(err, msg, session, resp, next)`
  159. * @memberOf Application
  160. */
  161. Application.globalAfter = function (af) {
  162. addFilter(this, Constants.KEYWORDS.GLOBAL_AFTER_FILTER, af);
  163. };
  164. /**
  165. * Add rpc before filter.
  166. *
  167. * @param {Object|Function} bf before fileter, bf(serverId, msg, opts, next)
  168. * @memberOf Application
  169. */
  170. Application.rpcBefore = function(bf) {
  171. addFilter(this, Constants.KEYWORDS.RPC_BEFORE_FILTER, bf);
  172. };
  173. /**
  174. * Add rpc after filter.
  175. *
  176. * @param {Object|Function} af after filter, `af(serverId, msg, opts, next)`
  177. * @memberOf Application
  178. */
  179. Application.rpcAfter = function(af) {
  180. addFilter(this, Constants.KEYWORDS.RPC_AFTER_FILTER, af);
  181. };
  182. /**
  183. * add a rpc filter to before and after rpc filter
  184. *
  185. * @param {Object} filter provide before and after filter method.
  186. * A filter should have two methods: before and after.
  187. * @memberOf Application
  188. */
  189. Application.rpcFilter = function(filter) {
  190. this.rpcBefore(filter);
  191. this.rpcAfter(filter);
  192. };
  193. /**
  194. * Load component
  195. *
  196. * @param {String} name (optional) name of the component
  197. * @param {Object} component component instance or factory function of the component
  198. * @param {[type]} opts (optional) construct parameters for the factory function
  199. * @return {Object} app instance for chain invoke
  200. * @memberOf Application
  201. */
  202. Application.load = function(name, component, opts) {
  203. if(typeof name !== 'string') {
  204. opts = component;
  205. component = name;
  206. name = null;
  207. if(typeof component.name === 'string') {
  208. name = component.name;
  209. }
  210. }
  211. if(typeof component === 'function') {
  212. component = component(this, opts);
  213. }
  214. if(!name && typeof component.name === 'string') {
  215. name = component.name;
  216. }
  217. if(name && this.components[name]) {
  218. // ignore duplicat component
  219. logger.warn('ignore duplicate component: %j', name);
  220. return;
  221. }
  222. this.loaded.push(component);
  223. if(name) {
  224. // components with a name would get by name throught app.components later.
  225. this.components[name] = component;
  226. }
  227. return this;
  228. };
  229. /**
  230. * Load Configure json file to settings.(support different enviroment directory & compatible for old path)
  231. *
  232. * @param {String} key environment key
  233. * @param {String} val environment value
  234. * @return {Server|Mixed} for chaining, or the setting value
  235. * @memberOf Application
  236. */
  237. Application.loadConfigBaseApp = function (key, val) {
  238. var env = this.get(Constants.RESERVED.ENV);
  239. var originPath = path.join(Application.getBase(), val);
  240. var presentPath = path.join(Application.getBase(), Constants.FILEPATH.CONFIG_DIR, env, path.basename(val));
  241. if(fs.existsSync(originPath)) {
  242. var file = require(originPath);
  243. if (file[env]) {
  244. file = file[env];
  245. }
  246. this.set(key, file);
  247. } else if(fs.existsSync(presentPath)) {
  248. var pfile = require(presentPath);
  249. this.set(key, pfile);
  250. } else {
  251. logger.error('invalid configuration with file path: %s', key);
  252. }
  253. };
  254. /**
  255. * Load Configure json file to settings.
  256. *
  257. * @param {String} key environment key
  258. * @param {String} val environment value
  259. * @return {Server|Mixed} for chaining, or the setting value
  260. * @memberOf Application
  261. */
  262. Application.loadConfig = function(key, val) {
  263. var env = this.get(Constants.RESERVED.ENV);
  264. val = require(val);
  265. if (val[env]) {
  266. val = val[env];
  267. }
  268. this.set(key, val);
  269. };
  270. /**
  271. * Set the route function for the specified server type.
  272. *
  273. * Examples:
  274. *
  275. * app.route('area', routeFunc);
  276. *
  277. * var routeFunc = function(session, msg, app, cb) {
  278. * // all request to area would be route to the first area server
  279. * var areas = app.getServersByType('area');
  280. * cb(null, areas[0].id);
  281. * };
  282. *
  283. * @param {String} serverType server type string
  284. * @param {Function} routeFunc route function. routeFunc(session, msg, app, cb)
  285. * @return {Object} current application instance for chain invoking
  286. * @memberOf Application
  287. */
  288. Application.route = function(serverType, routeFunc) {
  289. var routes = this.get(Constants.KEYWORDS.ROUTE);
  290. if(!routes) {
  291. routes = {};
  292. this.set(Constants.KEYWORDS.ROUTE, routes);
  293. }
  294. routes[serverType] = routeFunc;
  295. return this;
  296. };
  297. /**
  298. * Set before stop function. It would perform before servers stop.
  299. *
  300. * @param {Function} fun before close function
  301. * @return {Void}
  302. * @memberOf Application
  303. */
  304. Application.beforeStopHook = function(fun) {
  305. logger.warn('this method was deprecated in pomelo 0.8');
  306. if(!!fun && typeof fun === 'function') {
  307. this.set(Constants.KEYWORDS.BEFORE_STOP_HOOK, fun);
  308. }
  309. };
  310. /**
  311. * Start application. It would load the default components and start all the loaded components.
  312. *
  313. * @param {Function} cb callback function
  314. * @memberOf Application
  315. */
  316. Application.start = function(cb) {
  317. this.startTime = Date.now();
  318. if(this.state > STATE_INITED) {
  319. utils.invokeCallback(cb, new Error('application has already start.'));
  320. return;
  321. }
  322. var self = this;
  323. appUtil.startByType(self, function() {
  324. appUtil.loadDefaultComponents(self);
  325. var startUp = function() {
  326. appUtil.optComponents(self.loaded, Constants.RESERVED.START, function(err) {
  327. self.state = STATE_START;
  328. if(err) {
  329. utils.invokeCallback(cb, err);
  330. } else {
  331. logger.info('%j enter after start...', self.getServerId());
  332. self.afterStart(cb);
  333. }
  334. });
  335. };
  336. var beforeFun = self.lifecycleCbs[Constants.LIFECYCLE.BEFORE_STARTUP];
  337. if(!!beforeFun) {
  338. beforeFun.call(null, self, startUp);
  339. } else {
  340. startUp();
  341. }
  342. });
  343. };
  344. /**
  345. * Lifecycle callback for after start.
  346. *
  347. * @param {Function} cb callback function
  348. * @return {Void}
  349. */
  350. Application.afterStart = function(cb) {
  351. if(this.state !== STATE_START) {
  352. utils.invokeCallback(cb, new Error('application is not running now.'));
  353. return;
  354. }
  355. var afterFun = this.lifecycleCbs[Constants.LIFECYCLE.AFTER_STARTUP];
  356. var self = this;
  357. appUtil.optComponents(this.loaded, Constants.RESERVED.AFTER_START, function(err) {
  358. self.state = STATE_STARTED;
  359. var id = self.getServerId();
  360. if(!err) {
  361. logger.info('%j finish start', id);
  362. }
  363. if(!!afterFun) {
  364. afterFun.call(null, self, function() {
  365. utils.invokeCallback(cb, err);
  366. });
  367. } else {
  368. utils.invokeCallback(cb, err);
  369. }
  370. var usedTime = Date.now() - self.startTime;
  371. logger.info('%j startup in %s ms', id, usedTime);
  372. self.event.emit(events.START_SERVER, id);
  373. });
  374. };
  375. /**
  376. * Stop components.
  377. *
  378. * @param {Boolean} force whether stop the app immediately
  379. */
  380. Application.stop = function(force) {
  381. if(this.state > STATE_STARTED) {
  382. logger.warn('[pomelo application] application is not running now.');
  383. return;
  384. }
  385. this.state = STATE_STOPED;
  386. var self = this;
  387. this.stopTimer = setTimeout(function() {
  388. process.exit(0);
  389. }, Constants.TIME.TIME_WAIT_STOP);
  390. var cancelShutDownTimer =function(){
  391. if(!!self.stopTimer) {
  392. clearTimeout(self.stopTimer);
  393. }
  394. };
  395. var shutDown = function() {
  396. appUtil.stopComps(self.loaded, 0, force, function() {
  397. cancelShutDownTimer();
  398. if(force) {
  399. process.exit(0);
  400. }
  401. });
  402. };
  403. var fun = this.get(Constants.KEYWORDS.BEFORE_STOP_HOOK);
  404. var stopFun = this.lifecycleCbs[Constants.LIFECYCLE.BEFORE_SHUTDOWN];
  405. if(!!stopFun) {
  406. stopFun.call(null, this, shutDown, cancelShutDownTimer);
  407. } else if(!!fun) {
  408. utils.invokeCallback(fun, self, shutDown, cancelShutDownTimer);
  409. } else {
  410. shutDown();
  411. }
  412. };
  413. /**
  414. * Assign `setting` to `val`, or return `setting`'s value.
  415. *
  416. * Example:
  417. *
  418. * app.set('key1', 'value1');
  419. * app.get('key1'); // 'value1'
  420. * app.key1; // undefined
  421. *
  422. * app.set('key2', 'value2', true);
  423. * app.get('key2'); // 'value2'
  424. * app.key2; // 'value2'
  425. *
  426. * @param {String} setting the setting of application
  427. * @param {String} val the setting's value
  428. * @param {Boolean} attach whether attach the settings to application
  429. * @return {Server|Mixed} for chaining, or the setting value
  430. * @memberOf Application
  431. */
  432. Application.set = function (setting, val, attach) {
  433. if (arguments.length === 1) {
  434. return this.settings[setting];
  435. }
  436. this.settings[setting] = val;
  437. if(attach) {
  438. this[setting] = val;
  439. }
  440. return this;
  441. };
  442. /**
  443. * Get property from setting
  444. *
  445. * @param {String} setting application setting
  446. * @return {String} val
  447. * @memberOf Application
  448. */
  449. Application.get = function (setting) {
  450. return this.settings[setting];
  451. };
  452. /**
  453. * Check if `setting` is enabled.
  454. *
  455. * @param {String} setting application setting
  456. * @return {Boolean}
  457. * @memberOf Application
  458. */
  459. Application.enabled = function (setting) {
  460. return !!this.get(setting);
  461. };
  462. /**
  463. * Check if `setting` is disabled.
  464. *
  465. * @param {String} setting application setting
  466. * @return {Boolean}
  467. * @memberOf Application
  468. */
  469. Application.disabled = function (setting) {
  470. return !this.get(setting);
  471. };
  472. /**
  473. * Enable `setting`.
  474. *
  475. * @param {String} setting application setting
  476. * @return {app} for chaining
  477. * @memberOf Application
  478. */
  479. Application.enable = function (setting) {
  480. return this.set(setting, true);
  481. };
  482. /**
  483. * Disable `setting`.
  484. *
  485. * @param {String} setting application setting
  486. * @return {app} for chaining
  487. * @memberOf Application
  488. */
  489. Application.disable = function (setting) {
  490. return this.set(setting, false);
  491. };
  492. /**
  493. * Configure callback for the specified env and server type.
  494. * When no env is specified that callback will
  495. * be invoked for all environments and when no type is specified
  496. * that callback will be invoked for all server types.
  497. *
  498. * Examples:
  499. *
  500. * app.configure(function(){
  501. * // executed for all envs and server types
  502. * });
  503. *
  504. * app.configure('development', function(){
  505. * // executed development env
  506. * });
  507. *
  508. * app.configure('development', 'connector', function(){
  509. * // executed for development env and connector server type
  510. * });
  511. *
  512. * @param {String} env application environment
  513. * @param {Function} fn callback function
  514. * @param {String} type server type
  515. * @return {Application} for chaining
  516. * @memberOf Application
  517. */
  518. Application.configure = function (env, type, fn) {
  519. var args = [].slice.call(arguments);
  520. fn = args.pop();
  521. env = type = Constants.RESERVED.ALL;
  522. if(args.length > 0) {
  523. env = args[0];
  524. }
  525. if(args.length > 1) {
  526. type = args[1];
  527. }
  528. if (env === Constants.RESERVED.ALL || contains(this.settings.env, env)) {
  529. if (type === Constants.RESERVED.ALL || contains(this.settings.serverType, type)) {
  530. fn.call(this);
  531. }
  532. }
  533. return this;
  534. };
  535. /**
  536. * Register admin modules. Admin modules is the extends point of the monitor system.
  537. *
  538. * @param {String} module (optional) module id or provoided by module.moduleId
  539. * @param {Object} module module object or factory function for module
  540. * @param {Object} opts construct parameter for module
  541. * @memberOf Application
  542. */
  543. Application.registerAdmin = function(moduleId, module, opts) {
  544. var modules = this.get(Constants.KEYWORDS.MODULE);
  545. if(!modules) {
  546. modules = {};
  547. this.set(Constants.KEYWORDS.MODULE, modules);
  548. }
  549. if(typeof moduleId !== 'string') {
  550. opts = module;
  551. module = moduleId;
  552. if(module) {
  553. moduleId = module.moduleId;
  554. }
  555. }
  556. if(!moduleId){
  557. return;
  558. }
  559. modules[moduleId] = {
  560. moduleId: moduleId,
  561. module: module,
  562. opts: opts
  563. };
  564. };
  565. /**
  566. * Use plugin.
  567. *
  568. * @param {Object} plugin plugin instance
  569. * @param {[type]} opts (optional) construct parameters for the factory function
  570. * @memberOf Application
  571. */
  572. Application.use = function(plugin, opts) {
  573. if(!plugin.components) {
  574. logger.error('invalid components, no components exist');
  575. return;
  576. }
  577. var self = this;
  578. opts = opts || {};
  579. var dir = path.dirname(plugin.components);
  580. if(!fs.existsSync(plugin.components)) {
  581. logger.error('fail to find components, find path: %s', plugin.components);
  582. return;
  583. }
  584. fs.readdirSync(plugin.components).forEach(function (filename) {
  585. if (!/\.js$/.test(filename)) {
  586. return;
  587. }
  588. var name = path.basename(filename, '.js');
  589. var param = opts[name] || {};
  590. var absolutePath = path.join(dir, Constants.DIR.COMPONENT, filename);
  591. if(!fs.existsSync(absolutePath)) {
  592. logger.error('component %s not exist at %s', name, absolutePath);
  593. } else {
  594. self.load(require(absolutePath), param);
  595. }
  596. });
  597. // load events
  598. if(!plugin.events) {
  599. return;
  600. } else {
  601. if(!fs.existsSync(plugin.events)) {
  602. logger.error('fail to find events, find path: %s', plugin.events);
  603. return;
  604. }
  605. fs.readdirSync(plugin.events).forEach(function (filename) {
  606. if (!/\.js$/.test(filename)) {
  607. return;
  608. }
  609. var absolutePath = path.join(dir, Constants.DIR.EVENT, filename);
  610. if(!fs.existsSync(absolutePath)) {
  611. logger.error('events %s not exist at %s', filename, absolutePath);
  612. } else {
  613. bindEvents(require(absolutePath), self);
  614. }
  615. });
  616. }
  617. };
  618. /**
  619. * Application transaction. Transcation includes conditions and handlers, if conditions are satisfied, handlers would be executed.
  620. * And you can set retry times to execute handlers. The transaction log is in file logs/transaction.log.
  621. *
  622. * @param {String} name transaction name
  623. * @param {Object} conditions functions which are called before transaction
  624. * @param {Object} handlers functions which are called during transaction
  625. * @param {Number} retry retry times to execute handlers if conditions are successfully executed
  626. * @memberOf Application
  627. */
  628. Application.transaction = function(name, conditions, handlers, retry) {
  629. appManager.transaction(name, conditions, handlers, retry);
  630. };
  631. /**
  632. * Get master server info.
  633. *
  634. * @return {Object} master server info, {id, host, port}
  635. * @memberOf Application
  636. */
  637. Application.getMaster = function() {
  638. return this.master;
  639. };
  640. /**
  641. * Get current server info.
  642. *
  643. * @return {Object} current server info, {id, serverType, host, port}
  644. * @memberOf Application
  645. */
  646. Application.getCurServer = function() {
  647. return this.curServer;
  648. };
  649. /**
  650. * Get current server id.
  651. *
  652. * @return {String|Number} current server id from servers.json
  653. * @memberOf Application
  654. */
  655. Application.getServerId = function() {
  656. return this.serverId;
  657. };
  658. /**
  659. * Get current server type.
  660. *
  661. * @return {String|Number} current server type from servers.json
  662. * @memberOf Application
  663. */
  664. Application.getServerType = function() {
  665. return this.serverType;
  666. };
  667. /**
  668. * Get all the current server infos.
  669. *
  670. * @return {Object} server info map, key: server id, value: server info
  671. * @memberOf Application
  672. */
  673. Application.getServers = function() {
  674. return this.servers;
  675. };
  676. /**
  677. * Get all server infos from servers.json.
  678. *
  679. * @return {Object} server info map, key: server id, value: server info
  680. * @memberOf Application
  681. */
  682. Application.getServersFromConfig = function() {
  683. return this.get(Constants.KEYWORDS.SERVER_MAP);
  684. };
  685. /**
  686. * Get all the server type.
  687. *
  688. * @return {Array} server type list
  689. * @memberOf Application
  690. */
  691. Application.getServerTypes = function() {
  692. return this.serverTypes;
  693. };
  694. /**
  695. * Get server info by server id from current server cluster.
  696. *
  697. * @param {String} serverId server id
  698. * @return {Object} server info or undefined
  699. * @memberOf Application
  700. */
  701. Application.getServerById = function(serverId) {
  702. return this.servers[serverId];
  703. };
  704. /**
  705. * Get server info by server id from servers.json.
  706. *
  707. * @param {String} serverId server id
  708. * @return {Object} server info or undefined
  709. * @memberOf Application
  710. */
  711. Application.getServerFromConfig = function(serverId) {
  712. return this.get(Constants.KEYWORDS.SERVER_MAP)[serverId];
  713. };
  714. /**
  715. * Get server infos by server type.
  716. *
  717. * @param {String} serverType server type
  718. * @return {Array} server info list
  719. * @memberOf Application
  720. */
  721. Application.getServersByType = function(serverType) {
  722. return this.serverTypeMaps[serverType];
  723. };
  724. /**
  725. * Check the server whether is a frontend server
  726. *
  727. * @param {server} server server info. it would check current server
  728. * if server not specified
  729. * @return {Boolean}
  730. *
  731. * @memberOf Application
  732. */
  733. Application.isFrontend = function(server) {
  734. server = server || this.getCurServer();
  735. return !!server && server.frontend === 'true';
  736. };
  737. /**
  738. * Check the server whether is a backend server
  739. *
  740. * @param {server} server server info. it would check current server
  741. * if server not specified
  742. * @return {Boolean}
  743. * @memberOf Application
  744. */
  745. Application.isBackend = function(server) {
  746. server = server || this.getCurServer();
  747. return !!server && !server.frontend;
  748. };
  749. /**
  750. * Check whether current server is a master server
  751. *
  752. * @return {Boolean}
  753. * @memberOf Application
  754. */
  755. Application.isMaster = function() {
  756. return this.serverType === Constants.RESERVED.MASTER;
  757. };
  758. /**
  759. * Add new server info to current application in runtime.
  760. *
  761. * @param {Array} servers new server info list
  762. * @memberOf Application
  763. */
  764. Application.addServers = function(servers) {
  765. if(!servers || !servers.length) {
  766. return;
  767. }
  768. var item, slist;
  769. for(var i=0, l=servers.length; i<l; i++) {
  770. item = servers[i];
  771. // update global server map
  772. this.servers[item.id] = item;
  773. // update global server type map
  774. slist = this.serverTypeMaps[item.serverType];
  775. if(!slist) {
  776. this.serverTypeMaps[item.serverType] = slist = [];
  777. }
  778. replaceServer(slist, item);
  779. // update global server type list
  780. if(this.serverTypes.indexOf(item.serverType) < 0) {
  781. this.serverTypes.push(item.serverType);
  782. }
  783. }
  784. this.event.emit(events.ADD_SERVERS, servers);
  785. };
  786. /**
  787. * Remove server info from current application at runtime.
  788. *
  789. * @param {Array} ids server id list
  790. * @memberOf Application
  791. */
  792. Application.removeServers = function(ids) {
  793. if(!ids || !ids.length) {
  794. return;
  795. }
  796. var id, item, slist;
  797. for(var i=0, l=ids.length; i<l; i++) {
  798. id = ids[i];
  799. item = this.servers[id];
  800. if(!item) {
  801. continue;
  802. }
  803. // clean global server map
  804. delete this.servers[id];
  805. // clean global server type map
  806. slist = this.serverTypeMaps[item.serverType];
  807. removeServer(slist, id);
  808. // TODO: should remove the server type if the slist is empty?
  809. }
  810. this.event.emit(events.REMOVE_SERVERS, ids);
  811. };
  812. /**
  813. * Replace server info from current application at runtime.
  814. *
  815. * @param {Object} server id map
  816. * @memberOf Application
  817. */
  818. Application.replaceServers = function(servers) {
  819. if(!servers){
  820. return;
  821. }
  822. this.servers = servers;
  823. this.serverTypeMaps = {};
  824. this.serverTypes = [];
  825. var serverArray = [];
  826. for(var id in servers){
  827. var server = servers[id];
  828. var serverType = server[Constants.RESERVED.SERVER_TYPE];
  829. var slist = this.serverTypeMaps[serverType];
  830. if(!slist) {
  831. this.serverTypeMaps[serverType] = slist = [];
  832. }
  833. this.serverTypeMaps[serverType].push(server);
  834. // update global server type list
  835. if(this.serverTypes.indexOf(serverType) < 0) {
  836. this.serverTypes.push(serverType);
  837. }
  838. serverArray.push(server);
  839. }
  840. this.event.emit(events.REPLACE_SERVERS, serverArray);
  841. };
  842. /**
  843. * Add crons from current application at runtime.
  844. *
  845. * @param {Array} crons new crons would be added in application
  846. * @memberOf Application
  847. */
  848. Application.addCrons = function(crons) {
  849. if(!crons || !crons.length) {
  850. logger.warn('crons is not defined.');
  851. return;
  852. }
  853. this.event.emit(events.ADD_CRONS, crons);
  854. };
  855. /**
  856. * Remove crons from current application at runtime.
  857. *
  858. * @param {Array} crons old crons would be removed in application
  859. * @memberOf Application
  860. */
  861. Application.removeCrons = function(crons) {
  862. if(!crons || !crons.length) {
  863. logger.warn('ids is not defined.');
  864. return;
  865. }
  866. this.event.emit(events.REMOVE_CRONS, crons);
  867. };
  868. var replaceServer = function(slist, serverInfo) {
  869. for(var i=0, l=slist.length; i<l; i++) {
  870. if(slist[i].id === serverInfo.id) {
  871. slist[i] = serverInfo;
  872. return;
  873. }
  874. }
  875. slist.push(serverInfo);
  876. };
  877. var removeServer = function(slist, id) {
  878. if(!slist || !slist.length) {
  879. return;
  880. }
  881. for(var i=0, l=slist.length; i<l; i++) {
  882. if(slist[i].id === id) {
  883. slist.splice(i, 1);
  884. return;
  885. }
  886. }
  887. };
  888. var contains = function(str, settings) {
  889. if(!settings) {
  890. return false;
  891. }
  892. var ts = settings.split("|");
  893. for(var i=0, l=ts.length; i<l; i++) {
  894. if(str === ts[i]) {
  895. return true;
  896. }
  897. }
  898. return false;
  899. };
  900. var bindEvents = function(Event, app) {
  901. var emethods = new Event(app);
  902. for(var m in emethods) {
  903. if(typeof emethods[m] === 'function') {
  904. app.event.on(m, emethods[m].bind(emethods));
  905. }
  906. }
  907. };
  908. var addFilter = function(app, type, filter) {
  909. var filters = app.get(type);
  910. if(!filters) {
  911. filters = [];
  912. app.set(type, filters);
  913. }
  914. filters.push(filter);
  915. };