appUtil.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. var async = require('async');
  2. var log = require('./log');
  3. var utils = require('./utils');
  4. var path = require('path');
  5. var fs = require('fs');
  6. var Constants = require('./constants');
  7. var starter = require('../master/starter');
  8. var logger = require('pomelo-logger').getLogger('pomelo', __filename);
  9. /**
  10. * Initialize application configuration.
  11. */
  12. module.exports.defaultConfiguration = function(app) {
  13. var args = parseArgs(process.argv);
  14. setupEnv(app, args);
  15. loadMaster(app);
  16. loadServers(app);
  17. processArgs(app, args);
  18. configLogger(app);
  19. loadLifecycle(app);
  20. };
  21. /**
  22. * Start servers by type.
  23. */
  24. module.exports.startByType = function(app, cb) {
  25. if(!!app.startId) {
  26. if(app.startId === Constants.RESERVED.MASTER) {
  27. utils.invokeCallback(cb);
  28. } else {
  29. starter.runServers(app);
  30. }
  31. } else {
  32. if(!!app.type && app.type !== Constants.RESERVED.ALL && app.type !== Constants.RESERVED.MASTER) {
  33. starter.runServers(app);
  34. } else {
  35. utils.invokeCallback(cb);
  36. }
  37. }
  38. };
  39. /**
  40. * Load default components for application.
  41. */
  42. module.exports.loadDefaultComponents = function(app) {
  43. var pomelo = require('../pomelo');
  44. // load system default components
  45. if (app.serverType === Constants.RESERVED.MASTER) {
  46. app.load(pomelo.master, app.get('masterConfig'));
  47. } else {
  48. app.load(pomelo.proxy, app.get('proxyConfig'));
  49. if (app.getCurServer().port) {
  50. app.load(pomelo.remote, app.get('remoteConfig'));
  51. }
  52. if (app.isFrontend()) {
  53. app.load(pomelo.connection, app.get('connectionConfig'));
  54. app.load(pomelo.connector, app.get('connectorConfig'));
  55. app.load(pomelo.session, app.get('sessionConfig'));
  56. // compatible for schedulerConfig
  57. if(app.get('schedulerConfig')) {
  58. app.load(pomelo.pushScheduler, app.get('schedulerConfig'));
  59. } else {
  60. app.load(pomelo.pushScheduler, app.get('pushSchedulerConfig'));
  61. }
  62. }
  63. app.load(pomelo.backendSession, app.get('backendSessionConfig'));
  64. app.load(pomelo.channel, app.get('channelConfig'));
  65. app.load(pomelo.server, app.get('serverConfig'));
  66. }
  67. app.load(pomelo.monitor, app.get('monitorConfig'));
  68. };
  69. /**
  70. * Stop components.
  71. *
  72. * @param {Array} comps component list
  73. * @param {Number} index current component index
  74. * @param {Boolean} force whether stop component immediately
  75. * @param {Function} cb
  76. */
  77. module.exports.stopComps = function(comps, index, force, cb) {
  78. if (index >= comps.length) {
  79. utils.invokeCallback(cb);
  80. return;
  81. }
  82. var comp = comps[index];
  83. if (typeof comp.stop === 'function') {
  84. comp.stop(force, function() {
  85. // ignore any error
  86. module.exports.stopComps(comps, index + 1, force, cb);
  87. });
  88. } else {
  89. module.exports.stopComps(comps, index + 1, force, cb);
  90. }
  91. };
  92. /**
  93. * Apply command to loaded components.
  94. * This method would invoke the component {method} in series.
  95. * Any component {method} return err, it would return err directly.
  96. *
  97. * @param {Array} comps loaded component list
  98. * @param {String} method component lifecycle method name, such as: start, stop
  99. * @param {Function} cb
  100. */
  101. module.exports.optComponents = function(comps, method, cb) {
  102. var i = 0;
  103. async.forEachSeries(comps, function(comp, done) {
  104. i++;
  105. if (typeof comp[method] === 'function') {
  106. comp[method](done);
  107. } else {
  108. done();
  109. }
  110. }, function(err) {
  111. if (err) {
  112. if(typeof err === 'string') {
  113. logger.error('fail to operate component, method: %s, err: %j', method, err);
  114. } else {
  115. logger.error('fail to operate component, method: %s, err: %j', method, err.stack);
  116. }
  117. }
  118. utils.invokeCallback(cb, err);
  119. });
  120. };
  121. /**
  122. * Load server info from config/servers.json.
  123. */
  124. var loadServers = function(app) {
  125. app.loadConfigBaseApp(Constants.RESERVED.SERVERS, Constants.FILEPATH.SERVER);
  126. var servers = app.get(Constants.RESERVED.SERVERS);
  127. var serverMap = {}, slist, i, l, server;
  128. for (var serverType in servers) {
  129. slist = servers[serverType];
  130. for (i = 0, l = slist.length; i < l; i++) {
  131. server = slist[i];
  132. server.serverType = serverType;
  133. if(server[Constants.RESERVED.CLUSTER_COUNT]) {
  134. utils.loadCluster(app, server, serverMap);
  135. continue;
  136. }
  137. serverMap[server.id] = server;
  138. if (server.wsPort) {
  139. logger.warn('wsPort is deprecated, use clientPort in frontend server instead, server: %j', server);
  140. }
  141. }
  142. }
  143. app.set(Constants.KEYWORDS.SERVER_MAP, serverMap);
  144. };
  145. /**
  146. * Load master info from config/master.json.
  147. */
  148. var loadMaster = function(app) {
  149. app.loadConfigBaseApp(Constants.RESERVED.MASTER, Constants.FILEPATH.MASTER);
  150. app.master = app.get(Constants.RESERVED.MASTER);
  151. };
  152. /**
  153. * Process server start command
  154. */
  155. var processArgs = function(app, args) {
  156. var serverType = args.serverType || Constants.RESERVED.MASTER;
  157. var serverId = args.id || app.getMaster().id;
  158. var mode = args.mode || Constants.RESERVED.CLUSTER;
  159. var masterha = args.masterha || 'false';
  160. var type = args.type || Constants.RESERVED.ALL;
  161. var startId = args.startId;
  162. app.set(Constants.RESERVED.MAIN, args.main, true);
  163. app.set(Constants.RESERVED.SERVER_TYPE, serverType, true);
  164. app.set(Constants.RESERVED.SERVER_ID, serverId, true);
  165. app.set(Constants.RESERVED.MODE, mode, true);
  166. app.set(Constants.RESERVED.TYPE, type, true);
  167. if(!!startId) {
  168. app.set(Constants.RESERVED.STARTID, startId, true);
  169. }
  170. if (serverType !== Constants.RESERVED.MASTER) {
  171. app.set(Constants.RESERVED.CURRENT_SERVER, args, true);
  172. } else {
  173. app.set(Constants.RESERVED.CURRENT_SERVER, app.getMaster(), true);
  174. }
  175. if (masterha === 'true') {
  176. app.master = args;
  177. app.set(Constants.RESERVED.CURRENT_SERVER, args, true);
  178. }
  179. };
  180. /**
  181. * Setup enviroment.
  182. */
  183. var setupEnv = function(app, args) {
  184. app.set(Constants.RESERVED.ENV, args.env || process.env.NODE_ENV || Constants.RESERVED.ENV_DEV, true);
  185. };
  186. /**
  187. * Configure custom logger.
  188. */
  189. var configLogger = function(app) {
  190. if (process.env.POMELO_LOGGER !== 'off') {
  191. var env = app.get(Constants.RESERVED.ENV);
  192. var originPath = path.join(app.getBase(), Constants.FILEPATH.LOG);
  193. var presentPath = path.join(app.getBase(), Constants.FILEPATH.CONFIG_DIR, env, path.basename(Constants.FILEPATH.LOG));
  194. if(fs.existsSync(originPath)) {
  195. log.configure(app, originPath);
  196. } else if(fs.existsSync(presentPath)) {
  197. log.configure(app, presentPath);
  198. } else {
  199. logger.error('logger file path configuration is error.');
  200. }
  201. }
  202. };
  203. /**
  204. * Parse command line arguments.
  205. *
  206. * @param args command line arguments
  207. *
  208. * @return Object argsMap map of arguments
  209. */
  210. var parseArgs = function(args) {
  211. var argsMap = {};
  212. var mainPos = 1;
  213. while (args[mainPos].indexOf('--') > 0) {
  214. mainPos++;
  215. }
  216. argsMap.main = args[mainPos];
  217. for (var i = (mainPos + 1); i < args.length; i++) {
  218. var arg = args[i];
  219. var sep = arg.indexOf('=');
  220. var key = arg.slice(0, sep);
  221. var value = arg.slice(sep + 1);
  222. if (!isNaN(Number(value)) && (value.indexOf('.') < 0)) {
  223. value = Number(value);
  224. }
  225. argsMap[key] = value;
  226. }
  227. return argsMap;
  228. };
  229. /**
  230. * Load lifecycle file.
  231. *
  232. */
  233. var loadLifecycle = function(app) {
  234. var filePath = path.join(app.getBase(), Constants.FILEPATH.SERVER_DIR, app.serverType, Constants.FILEPATH.LIFECYCLE);
  235. if(!fs.existsSync(filePath)) {
  236. return;
  237. }
  238. var lifecycle = require(filePath);
  239. for(var key in lifecycle) {
  240. if(typeof lifecycle[key] === 'function') {
  241. app.lifecycleCbs[key] = lifecycle[key];
  242. } else {
  243. logger.warn('lifecycle.js in %s is error format.', filePath);
  244. }
  245. }
  246. };