pomelo 框架第一部分
作者:互联网
pomelo 框架第一部分
项目地址: https://github.com/NetEase/chatofpomelo-websocket.git
分支:tutorial-protobuf
一、pomelo.js
pomelo.js中的初始化
Pomelo.connectors = {};
Pomelo.connectors.__defineGetter__('sioconnector', load.bind(null, './connectors/sioconnector'));
Pomelo.connectors.__defineGetter__('hybridconnector', load.bind(null, './connectors/hybridconnector'));
Pomelo.connectors.__defineGetter__('udpconnector', load.bind(null, './connectors/udpconnector'));
Pomelo.connectors.__defineGetter__('mqttconnector', load.bind(null, './connectors/mqttconnector'));
function load(path, name) {
if (name) {
return require(path + name);
}
return require(path);
}
defineGetter 方法可以将一个函数绑定在当前对象的指定属性上,当那个属性的值被读取时,你所绑定的函数就会被调用。
通过 defineGetter 和 load.bind 给Pomelo.connectors绑定相应属性,如:sioconnector、hybridconnector、udpconnector、mqttconnector。
pomelo/lib/components
fs.readdirSync(__dirname + '/components').forEach(function (filename) {
if (!/\.js$/.test(filename)) {
return;
}
var name = path.basename(filename, '.js');
var _load = load.bind(null, './components/', name);
Pomelo.components.__defineGetter__(name, _load);
Pomelo.__defineGetter__(name, _load);
});
pomelo/lib/filters/handler
fs.readdirSync(__dirname + '/filters/handler').forEach(function (filename) {
if (!/\.js$/.test(filename)) {
return;
}
var name = path.basename(filename, '.js');
var _load = load.bind(null, './filters/handler/', name);
Pomelo.filters.__defineGetter__(name, _load);
Pomelo.__defineGetter__(name, _load);
});
pomelo/lib/filters/rpc
fs.readdirSync(__dirname + '/filters/rpc').forEach(function (filename) {
if (!/\.js$/.test(filename)) {
return;
}
var name = path.basename(filename, '.js');
var _load = load.bind(null, './filters/rpc/', name);
Pomelo.rpcFilters.__defineGetter__(name, _load);
});
通过读取相应文件夹下的文件,根据文件的名字绑定到相应的属性上面。
二、项目启动
1.creaeApp方法
app.js 中,var app = pomelo.createApp();
调用pomelo.js 中的Pomelo.createApp
方法:
Pomelo.createApp = function (opts) {
var app = application;
app.init(opts);
self.app = app;
return app;
};
通过createApp方法,对application进行初始化,并返回app实例。
2.app.init(opts)
application.js 中 Application.init
① 设置初始值
② 调用appUtil.defaultConfiguration(this);
读取配置
③ 设置this.state = 1
3.appUtil.defaultConfiguration(this)
/ util / appUtil.js 中 defaultConfiguration
var args = parseArgs(process.argv); // main: 'chatofpomelo-websocket/game-server/app.js'
setupEnv(app, args); // 设置服务器的运行环境
loadMaster(app); // 加载master.json文件
loadServers(app); // 加载servers.json文件
processArgs(app, args); // 根据进程参数设置app属性
configLogger(app); // 加载log4js.json
loadLifecycle(app); // 加载生命周期
4.app.js中加载配置
app.js
app.configure('production|development', 'connector', function(){ // 运行环境、服务器类型
app.set('connectorConfig', // 属性名称
{
connector : pomelo.connectors.hybridconnector, // connector类型
heartbeat : 3, // 心跳时间
useDict : true, // 是否开启字典
useProtobuf : true // 是否开启Protobuf
});
});
根据参数配置,设置connectorConfig属性到app上,如上:connector类型选择了hybridconnector,心跳时间为3秒,开启字典以及protobuf。
app.js
app.configure('production|development', function() {
app.route('chat', chatRoute); // 设置chat服务器的分配route规则
app.filter(pomelo.timeout()); // 添加超时过滤器
});
根据参数配置,设置chat服务器的路由分配规则,并添加超时过滤器。
如果未指定路由分配规则,则按pomelo默认路由分配规则进行路由分配。
application.js
Application.route = function(serverType, routeFunc) {
var routes = this.get(Constants.KEYWORDS.ROUTE);
if(!routes) {
routes = {};
this.set(Constants.KEYWORDS.ROUTE, routes);
}
routes[serverType] = routeFunc;
return this;
};
根据不同的服务器类型,给__routes__属性绑定路由分配规则。
proxy.js
var defaultRoute = function(session, msg, app, cb) {
var list = app.getServersByType(msg.serverType);
if (!list || !list.length) {
cb(new Error('can not find server info for type:' + msg.serverType));
return;
}
var uid = session ? (session.uid || '') : '';
var index = Math.abs(crc.crc32(uid.toString())) % list.length;
utils.invokeCallback(cb, null, list[index].id);
};
此为默认路由分配规则,在proxy.js初始化时进行指定路由分配规则,根据__routes__属性中是否有自定义的路由分配,进行不同的赋值。
app.js
app.configure('production|development', 'chat', function() {
app.filter(abuseFilter());
});
为chat服务器添加自定义过滤器abuseFilter。
application.js
Application.filter = function (filter) {
this.before(filter);
this.after(filter);
};
Application.before = function (bf) {
addFilter(this, Constants.KEYWORDS.BEFORE_FILTER, bf);
};
Application.after = function (af) {
addFilter(this, Constants.KEYWORDS.AFTER_FILTER, af);
};
var addFilter = function(app, type, filter) {
var filters = app.get(type);
if(!filters) {
filters = [];
app.set(type, filters);
}
filters.push(filter);
};
pomelo过滤器分为前置过滤器和后置过滤器,handler在before和after之间,根据配置过滤器,指定到app的__befores__和__afters__上。
5.app.start
app.start();
调用application的start方法。
二、application.start
1.application.start
application.js
Application.start = function (cb) {
this.startTime = Date.now();
if (this.state > STATE_INITED) {
utils.invokeCallback(cb, new Error('application has already start.'));
return;
}
var self = this;
appUtil.startByType(self, function () {
appUtil.loadDefaultComponents(self); // 加载组件
var startUp = function () {
appUtil.optComponents(self.loaded, Constants.RESERVED.START, function (err) { // 调用self.loaded中组件的start方法
self.state = STATE_START;
if (err) {
utils.invokeCallback(cb, err);
} else {
logger.info('%j enter after start...', self.getServerId());
self.afterStart(cb); // 调用application的afterStart方法
}
});
};
var beforeFun = self.lifecycleCbs[Constants.LIFECYCLE.BEFORE_STARTUP];
if (!!beforeFun) {
beforeFun.call(null, self, startUp);
} else {
startUp();
}
});
};
application.start
的功能主要是,加载默认组件,启动组件,所有组件启动完成后,改变application的state属性为2,然后调用afterStart方法,继续后续调用。
2.appUtil.loadDefaultComponents(self);
appUtil.js
module.exports.loadDefaultComponents = function (app) {
var pomelo = require('../pomelo');
// load system default components
if (app.serverType === Constants.RESERVED.MASTER) {
app.load(pomelo.master, app.get('masterConfig'));
} else {
app.load(pomelo.proxy, app.get('proxyConfig'));
if (app.getCurServer().port) {
app.load(pomelo.remote, app.get('remoteConfig'));
}
if (app.isFrontend()) {
app.load(pomelo.connection, app.get('connectionConfig'));
app.load(pomelo.connector, app.get('connectorConfig'));
app.load(pomelo.session, app.get('sessionConfig'));
// compatible for schedulerConfig
if (app.get('schedulerConfig')) {
app.load(pomelo.pushScheduler, app.get('schedulerConfig'));
} else {
app.load(pomelo.pushScheduler, app.get('pushSchedulerConfig'));
}
}
app.load(pomelo.backendSession, app.get('backendSessionConfig'));
app.load(pomelo.channel, app.get('channelConfig'));
app.load(pomelo.server, app.get('serverConfig'));
}
app.load(pomelo.monitor, app.get('monitorConfig'));
};
loadDefaultComponents
根据服务器类型,加载不同的组件。
-
master 服务器
- 加载 master组件和 monitor组件 非 master 服务器
- 加载 proxy 组件、 backendSession 组件、 channel 组件和 server 组件
- app.getCurServer().port: 加载 remote 组件
- app.isFrontend: 加载 connection 组件、 connector 组件、 session 组件和 pushScheduler 组件
3. application.load
application.js
Application.load = function (name, component, opts) {
if (typeof name !== 'string') {
opts = component;
component = name;
name = null;
if (typeof component.name === 'string') {
name = component.name;
}
}
if (typeof component === 'function') {
component = component(this, opts); // 初始化相应组件
}
if (!name && typeof component.name === 'string') {
name = component.name;
}
if (name && this.components[name]) {
// ignore duplicat component
logger.warn('ignore duplicate component: %j', name);
return;
}
this.loaded.push(component); // 加载到loaded中
if (name) {
// components with a name would get by name throught app.components later.
this.components[name] = component; // 加载到components中
}
return this;
};
初始化相应组件,然后把组件添加到 app.loaded 和 app.components 属性中。
4.appUtil.optComponents
module.exports.optComponents = function (comps, method, cb) {
var i = 0;
async.forEachSeries(comps, function (comp, done) {
i++;
if (typeof comp[method] === 'function') { // 如果此模块中包含method方法,执行
comp[method](done);
} else {
done();
}
}, function (err) {
if (err) {
if (typeof err === 'string') {
logger.error('fail to operate component, method: %s, err: %j', method, err);
} else {
logger.error('fail to operate component, method: %s, err: %j', method, err.stack);
}
}
utils.invokeCallback(cb, err);
});
};
appUtil.optComponents
执行相应的method方法。
5.application.afterStart
Application.afterStart = function (cb) {
if (this.state !== STATE_START) {
utils.invokeCallback(cb, new Error('application is not running now.'));
return;
}
var afterFun = this.lifecycleCbs[Constants.LIFECYCLE.AFTER_STARTUP];
var self = this;
appUtil.optComponents(this.loaded, Constants.RESERVED.AFTER_START, function (err) { // 调用self.loaded中组件的afterStart方法
self.state = STATE_STARTED;
var id = self.getServerId();
if (!err) {
logger.info('%j finish start', id);
}
if (!!afterFun) {
afterFun.call(null, self, function () {
utils.invokeCallback(cb, err);
});
} else {
utils.invokeCallback(cb, err);
}
var usedTime = Date.now() - self.startTime;
logger.info('%j startup in %s ms', id, usedTime);
self.event.emit(events.START_SERVER, id); // emit start_server 监听
});
};
application.afterStart
调用app.loaded 中 afterStart方法,执行完后,emit start_server 监听
三、模块启动 lib/components
1.backendSession.js
初始化BackendSessionService,设置backendSessionService
和localSessionService
name = __backendSession__
var service = new BackendSessionService(app);
app.set('backendSessionService', service, true);
app.set('localSessionService', service, true);
2.channel.js
初始化ChannelService,设置channelService
name = __channel__
var service = new ChannelService(app, opts);
app.set('channelService', service, true);
3.connection.js
用于前端服务器统计连接状态的连接组件(connection)。
初始化ConnectionService,把ConnectionService
上的方法除了start
和stop
绑定到this.service
name = __connection__
this.app = app;
this.service = new ConnectionService(app);
// proxy the service methods except the lifecycle interfaces of component
var method, self = this;
var getFun = function (m) {
return (function () {
return function () {
return self.service[m].apply(self.service, arguments);
};
})();
};
for (var m in this.service) {
if (m !== 'start' && m !== 'stop') {
method = this.service[m];
if (typeof method === 'function') {
this[m] = getFun(m);
}
}
}
4.connector.js
连接器组件(connector), 接收客户端请求并使用套接字附加会话。
name = __connector__
this.connector = getConnector(app, opts); // 初始化connector
this.encode = opts.encode; // 编码
this.decode = opts.decode; // 解码
if (opts.useDict) { // 字典
app.load(pomelo.dictionary, app.get('dictionaryConfig')); // 加载字典
}
if (opts.useProtobuf) { // protobuf
app.load(pomelo.protobuf, app.get('protobufConfig')); // 加载protobuf
}
在app.js中对connectorConfig
属性进行了赋值,application 调用start时调用了appUtil中的loadDefaultComponents
方法,在app.loaded
时取connectorConfig
属性,对connector进行初始化。
connector : pomelo.connectors.hybridconnector
因为connector为hybridconnector,所以getConnector(app, opts
)是对hybridconnector进行初始化,即:connector = hybridconnector(clientPort, host, opts)。
5.dictionary.js
读取'/config/dictionary.json'
配置文件,对其this.userDicPath
属性进行赋值。
name = __dictionary__
6.master.js
初始化master
name = __master__
var Master = require('../master/master');
this.master = new Master(app, opts);
6.monitor.js
初始化monitor
name = __monitor__
var Master = require('../monitor/monitor');
this.monitor = new Monitor(app, opts);
7.protobuf.js
读取'/config/serverProtos.json'
和'/config/clientProtos.json'
配置文件,对protobuf进行初始化操作。
name = __protobuf__
8.proxy.js
代理组件。为rpc客户端生成代理。
name = __proxy__
获取proxyConfig
属性中的值,对proxy进行初始化赋值操作。
opts.bufferMsg = opts.bufferMsg || opts.cacheMsg || false;
opts.interval = opts.interval || 30;
opts.router = genRouteFun();
return new Component(app, opts);
获取__routes__
属性,如果在app.js中有自定义操作,那根据自定义规则进行赋值,如果没有自定义,则按默认方法进行赋值
var genRouteFun = function () {
return function (session, msg, app, cb) {
var routes = app.get('__routes__'); // 获取__routes__属性
if (!routes) {
defaultRoute(session, msg, app, cb);
return;
}
var type = msg.serverType, route = routes[type] || routes['default'];
if (route) {
route(session, msg, app, cb); // 自定义路由
} else {
defaultRoute(session, msg, app, cb); // 默认路由
}
};
};
对this.client
进行初始化,进而监听ADD_SERVERS
、REMOVE_SERVERS
、REPLACE_SERVERS
var Component = function(app, opts) {
this.app = app;
this.opts = opts;
this.client = genRpcClient(this.app, opts); // require('pomelo-rpc').client
this.app.event.on(events.ADD_SERVERS, this.addServers.bind(this));
this.app.event.on(events.REMOVE_SERVERS, this.removeServers.bind(this));
this.app.event.on(events.REPLACE_SERVERS, this.replaceServers.bind(this));
};
9.pushScheduler.js
调度程序组件,用于调度消息发送。
name = __pushScheduler__
获取调度算法,可自定义,如果没有自定义,即默认调度方法
this.scheduler = getScheduler(this, app, opts);
10.remote.js
远程服务的组件,加载远程服务并添加到全局上下文。
name = __remote__
获取remoteConfig
属性中的值,对remote进行初始化赋值操作。
11.server.js
服务器启动组件。
name = __server__
this.server = Server.create(app, opts);
初始化server/server.js
12.session.js
session组件,管理session
name = __session__
初始化SessionService,把SessionService
上的方法除了start
和stop
绑定到this.service
this.service = new SessionService(opts);
以上组件中:
master、monitor、proxy、remote、channel、server、dictionary、connector中包含start
标签:__,function,框架,第一,app,js,pomelo,var,name 来源: https://blog.csdn.net/ai_milk/article/details/114259122