pomelo之application的创建于初始化

距离上一篇pomelo已经有一段时间了吧,总是有一些事情要做。。

这一篇来写pomelo的application的创建过程。。当然例子还是以官方的chat。。。。主要是来分析下面这段代码:

var app = pomelo.createApp();

我们首先来看看pomelo的定义吧:

var fs = require('fs');
var path = require('path');
var application = require('./application');


/**
 * Expose `createApplication()`.
 *
 * @module
 */
//这里相当于是进行命名
var Pomelo = module.exports = {};

/**
 * Framework version.
 */

Pomelo.version = '0.4';

/**
 * Event definitions that would be emitted by app.event
 */
Pomelo.events = require('./util/events');

/**
 * auto loaded components
 */
 //用于保存组件
Pomelo.components = {};

/**
 * auto loaded filters
 */
 //用于保存filter
Pomelo.filters = {};

/**
 * connectors
 */
 //connector对象
Pomelo.connectors = {};
//connector对象的get方法
Pomelo.connectors.__defineGetter__('sioconnector', function() {
  return require('./connectors/sioconnector');
});
//超级connector的get方法
Pomelo.connectors.__defineGetter__('hybridconnector', function() {
  return require('./connectors/hybridconnector');
});

/**
 * schedulers
 */
 //定义调度器
Pomelo.schedulers = {};
Pomelo.schedulers.__defineGetter__('direct', function() {
  var m = require('./scheduler/direct');
  return m;
});

Pomelo.schedulers.__defineGetter__('buffer', function() {
  return require('./scheduler/buffer');
});

/**
 * global channel manager
 */
Pomelo.connectors.__defineGetter__('redisGlobalChannelManager', function() {
  return require('./common/manager/redisGlobalChannelManager');
});

//用self来指向当前的作用域
var self = this;

/**
 * Create an pomelo application.
 *
 * @return {Application}
 * @memberOf Pomelo
 * @api public
 */
 //创建application对象
Pomelo.createApp = function (opts) {
  var app = application;
  app.init(opts);  //初始化函数
  self.app = app;
  return app;
};

/**
 * Get application
 */
 //相当于是为Pomelo对象添加一个属性,app,它是一个对象,就存在一个get方法,用于返回当前的app对象
Object.defineProperty(Pomelo, 'app', {
  get:function () {
    return self.app;
  }
});

/**
 * Auto-load bundled components with getters.
 */
 //用于在components文件夹中读取组件,然后保存到components对象里面去
fs.readdirSync(__dirname + '/components').forEach(function (filename) {
  if (!/\.js$/.test(filename)) {
    return;
  }
  var name = path.basename(filename, '.js');

  function load() {
    return require('./components/' + name);
  }
  Pomelo.components.__defineGetter__(name, load);//例如执行Pomelo.components.aa,其实会得到require("./components/aa");的值
  Pomelo.__defineGetter__(name, load);
});

//用于读取filter对象
fs.readdirSync(__dirname + '/filters/handler').forEach(function (filename) {
  if (!/\.js$/.test(filename)) {
    return;
  }
  var name = path.basename(filename, '.js');

  function load() {
    return require('./filters/handler/' + name);
  }
  Pomelo.filters.__defineGetter__(name, load);
  Pomelo.__defineGetter__(name, load);
});
其实本身pomelo的定义还是很简单的,无非就是定义了一些名字,然后加载了一些组件,这里其实可以将pomelo对象看成已是一个资源的管理。。。

这里大量用到了如下的方法:

Pomelo.connectors.__defineGetter__('redisGlobalChannelManager', function() {
  return require('./common/manager/redisGlobalChannelManager');
});
这种用法其实就是定义一下这个属性的获取方法,当Pomelo.connectors.redisGlobalChannelManager的方式访问这个属性的时候,会直接调用换进去的函数,得到返回值。。。

我们重点来分析如下代码:

 //创建application对象
Pomelo.createApp = function (opts) {
  var app = application;
  app.init(opts);  //初始化函数
  self.app = app;
  return app;
};
由于application的定义比较长,就不一次性列出来,先来看看它的init方法。。。。
Application.init = function(opts) {
  opts = opts || {};
  this.loaded = [];       // loaded component list
  //用于保存所有的组件
  this.components = {};   // name -> component map

  //调用set方法保存的参数将会保存在这个地方
  this.settings = {};     // collection keep set/get
  this.set('base', opts.base);
  //事件对象
  this.event = new EventEmitter();  // event object to sub/pub events

  // current server info
  this.serverId = null;   // current server id
  this.serverType = null; // current server type
  this.curServer = null;  // current server info

  // global server infos
  this.master = null;         // master server info
  //用于保存所有的server,id与info的键值对
  this.servers = {};          // current global server info maps, id -> info
  this.serverTypeMaps = {};   // current global type maps, type -> [info]
  this.serverTypes = [];      // current global server type list

  appUtil.defaultConfiguration(this);   //默认配置

  this.state = STATE_INITED;  //将当前的状态修改为已经初始化
  logger.info('application inited: %j', this.getServerId());
};
刚开始启动的视乎,没有参数传进来,opts就是null,代码本身也很简单吧,可以当做是对application对象的一些属性的声明和初始化。。。

这里主要是要看一下defaultConfiguration部分干了些什么。。。

我们来看看它的定义吧:

module.exports.defaultConfiguration = function (app) {
  var args = parseArgs(process.argv);  //这里process.argv保存的是运行使用的命令,是一个数组例如[ 'node', '/home/fjs/Desktop/pomelo/game-server/app.js' ]
  /*
  [ '/usr/local/bin/node',
  '/home/fjs/Desktop/pomelo/game-server/app.js',
  'env=development',
  'id=chat-server-2',
  'host=127.0.0.1',
  'port=6051',
  'serverType=chat' ]
*/

  //最后args如以下形式:
  //master { main: '/home/fjs/Desktop/pomelo/game-server/app.js' }

  /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js',
  env: 'development',
  id: 'connector-server-1',
  host: '127.0.0.1',
  port: 4050,
  clientPort: 3050,
  frontend: 'true',
  serverType: 'connector' }*/

  setupEnv(app, args);    //设置当前环境的配置,是开发,部署等
  loadMaster(app);    //加载master服务器的配置
  loadServers(app);   //加载server的配置
  processArgs(app, args);
  configLogger(app);
};
代码还是很简单吧,先是获取当前的执行命令,例如:node app.js,

然后对其进行一些处理,将一些参数处理出来,这里可能要分为两种,毕竟有master服务器和非master服务器。。。他们解析出来的结果在上面的注释都已经标了出来。。。

接下来就是设置环境,例如是development或者production。。。

然后载入Master服务器的配置,然后载入普通server的配置。。。

这里我们就选一个出来看看吧,看看普通server的配置是怎么进行载入的。。。

var loadServers = function(app) {
  app.loadConfig('servers', app.getBase() + '/config/servers.json');  //载入server类型的服务器的配置
  var servers = app.get('servers');   //获取刚刚载入的配置信息
  var serverMap = {}, slist, i, l, server;
  for(var serverType in servers) {   //遍历serve的类型,chat,gate,connector
    slist = servers[serverType];
    for(i=0, l=slist.length; i<l; i++) {    //遍历当前这种类型的server
      server = slist[i];
      server.serverType = serverType;
      serverMap[server.id] = server;   //将这些server保存到serverMap里面去

      if(server.wsPort) {
        logger.warn('wsPort is deprecated, ' +
                    'use clientPort and frontend instead.');
      }
    }
  }

  app.set('__serverMap__', serverMap);  //将所有的server保存到app域里去
};
代码还是很简单的吧,首先载入配置文件,然后遍历其中server类型,然后将他们用键值对管理起来就完事了。。。

额。。

最后还有一个  processArgs(app, args);

var processArgs = function(app, args){
  var serverType = args.serverType || 'master';   //如果没有serverType,那么就是master服务器了
  var serverId = args.id || app.getMaster().id;    //获取服务器的id

  app.set('main', args.main, true);    //将运行信息保存起来,
    //master { main: '/home/fjs/Desktop/pomelo/game-server/app.js' }

  /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js',
  env: 'development',
  id: 'connector-server-1',
  host: '127.0.0.1',
  port: 4050,
  clientPort: 3050,
  frontend: 'true',
  serverType: 'connector' }*/
  app.set('serverType', serverType, true);
  app.set('serverId', serverId, true);

 if(serverType !== 'master') {  //保存当前服务器类型
    app.set('curServer', args, true);
  } else {
    app.set('curServer', app.getMaster(), true);   
  }
};
其实这个名字有点唬人,并没有执行什么命令,无非是设置了一些参数而已,。。。。。


好了,那么整个application的创建过程就差不多了,其实这部分最主要的事情还是将配置文件load进来。。。


下一篇来分析一下启动过程吧。。。。

你可能感兴趣的:(pomelo之application的创建于初始化)