距离上一篇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进来。。。
下一篇来分析一下启动过程吧。。。。