距離上一篇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進來。。。
下一篇來分析一下啟動過程吧。