在前面的一篇文章中知道了connector组件的作用,而且知道了,connector接收到数据之后,会调用server组件的handle方法来处理这些数据,那么这篇文章我们就来看看server组件究竟是怎么进行工作的吧。。。
首先我们来看看server组件的包装器的定义:
/**
* Component for server starup.
*/
var Server = require('../server/server');
/**
* Component factory function
*
* @param {Object} app current application context
* @return {Object} component instance
*/
module.exports = function(app) {
return new Component(app);
};
/**
* Server component class
*
* @param {Object} app current application context
*/
var Component = function(app) {
this.server = Server.create(app); //用于创建真正的server组件
};
Component.prototype.name = '__server__';
/**
* Component lifecycle callback
*
* @param {Function} cb
* @return {Void}
*/
Component.prototype.start = function(cb) { //启动
this.server.start();
process.nextTick(cb);
};
/**
* Component lifecycle function
*
* @param {Boolean} force whether stop the component immediately
* @param {Function} cb
* @return {Void}
*/
Component.prototype.stop = function(force, cb) {
this.server.stop();
process.nextTick(cb);
};
/**
* Proxy server.handle
*/
Component.prototype.handle = function(msg, session, cb) { //调用server的hanlder来处理接收到的数据,用cb来处理返回的数据
this.server.handle(msg, session, cb);
};
这里无非就是对内部的server进行了一个代理,尤其是handle方法,直接就是调用的内部server的handle方法进行处
理的,好吧,那么我们接下来来看看这个内部的server究竟是怎么定义的吧,首先来看看它的构造函数:
module.exports.create = function(app) {
return new Server(app);
};
//这个可以看成是server的构造函数吧
var Server = function (app) {
this.app = app;
this.filterService = null;
this.handlerService = null;
this.state = ST_INITED;
};
var pro = Server.prototype;
这里应该是没有什么重要的信息,无非就是设置了一些属性,其实干货比较多的过程在于start部分,来看看先:
pro.start = function() {
if(this.state > ST_INITED) {
return;
}
this.filterService = initFilter(this.app); //初始化filter函数
this.handlerService = initHandler(this.app); //初始化handler
this.state = ST_STARTED;
};
这里代码通过名字就知道要干一些什么事情了,初始化了filter,然后还初始化了handler,这里就是暂时不看filter部分的内容吧,来看看这个handler是怎么进行初始化的。。。
//创建handlerservice
var initHandler = function(app) {
return new HandlerService(app, loadHandlers(app));
};
好吧,其实这里创建的是一个handlerservice,在创建它的同时,还要进行handler的load,来看看handler是怎么load的吧:
//为当前的server加载它的handler
var loadHandlers = function(app) {
var p = pathUtil.getHandlerPath(app.getBase(), app.getServerType()); //用于根据server的类型来加载相应的handler
if(p) {
return Loader.load(p, app); //加载handler
}
};
这个就是handler的load过程,这里就不细看了,我们已经知道pomelo可以自己定义服务器类型,例如我们例子中用的chat,那么当启动相应的服务器的时候,就会从相应的文件夹里面去载入文件,从而完成handler的load过程,其实这个样子看起来很像ruby on rails的方式。。。里面load的过程,其实就是一些读取文件夹,读文件等,就不细究了。。那么接下来来看看handlerservice是怎么定义的吧,先来看看它的构造函数:
var Service = function(app, handlers) {
this.app = app;
this.handlers = handlers || {};
};
很简单吧,无非就是保存一下app和handlers。。。
好了,那么接下来来看看server组件处理数据的流程吧,先来看最外面的server包装器它的handle方法:
Component.prototype.handle = function(msg, session, cb) { //调用server的hanlder来处理接收到的数据,用cb来处理返回的数据
this.server.handle(msg, session, cb);
};
没什么意思,不过这里需要说明的是,cb回调函数是在connector里面传过来的,handler处理完成后,可以调用cb将数据返回给客户端。。。。。以后会看到的。。
好了,接下来来深入内部看看吧:
//调用handler来处理信息
pro.handle = function(msg, session, cb) {
if(this.state !== ST_STARTED) {
cb(new Error('server not started'));
return;
}
var routeRecord = parseRoute(msg.route); //用于解析route参数
if(!routeRecord) {
cb(new Error('meet unknown route message %j', msg.route));
return;
}
if(this.app.getServerType() !== routeRecord.serverType) { //判断route的路径是否是到当前的服务器
doForward(this.app, msg, session, routeRecord, cb); //如果类型不符的话,那么用符合的服务器来处理
} else {
doHandle(this, msg, session, routeRecord, cb); //符合,那么用当前的handler来处理
}
};
首先是解析发送过来的数据的route信息,包含了server的类型,所访问的handler的类型,方法的名字等等。。然后再判断当前服务器类型与要访问的服务器类型是否相同,如果不相同的话,那么需要进行远程调用,将这些参数传给合适的服务器进行处理,这里就不细看,以后会讲的,就先看看相同的情况下把,会调用当前服务器的handler进行处理:
//这里调用用户定义的handler来处理数据
var doHandle = function(server, msg, session, routeRecord, cb) {
var originMsg = msg;
msg = msg.body || {};
msg.__route__ = originMsg.route; //相当于是保存route数据
var self = server;
var handle = function(err, resp) {
if(err) {
// error from before filter
handleError(self, err, msg, session, resp, function(err, resp) {
response(self, err, msg, session, resp, cb);
});
return;
}
//调用handler进行处理
self.handlerService.handle(routeRecord, msg, session, function(err, resp) {
if(err) {
//error from handler
handleError(self, err, msg, session, resp, function(err, resp) {
response(self, err, msg, session, resp, cb);
});
return;
}
response(self, err, msg, session, resp, cb); //相当于是向客户端返回信息
});
}; //end of handle
beforeFilter(server, msg, session, handle);
};
在调用之前,会先执行filter函数,在调用之后也要执行filter函数,这里其实是调用内部的handlerservice进行处理这些数据的,那么来看看handlerservice的handle方法吧:
Service.prototype.handle = function(routeRecord, msg, session, cb){
// the request should be processed by current server
var handler = getHandler(this.handlers, routeRecord); //根据handdler的名字获取handler
if(!handler) {
logger.error('[handleManager]: fail to find handler for %j', msg.__route__);
cb(new Error('fail to find handler for ' + msg.__route__));
return;
}
var start = Date.now();
handler[routeRecord.method](msg, session, function(err,resp){ //相当于是根据method的名字来执行相应的方法,传入的额函数就是handler里的next参数,用于将返回的数据发送给客户端
var log = {
route : msg.__route__,
args : msg,
time : utils.format(new Date(start)),
timeUsed : new Date() - start
};
forward_logger.info(JSON.stringify(log));
cb(err,resp);
});
return;
};
感觉这里已经很简单了吧,无非就是根据前面的一些route的信息,找到相应的方法,然后由其来处理,然后再将返回的信息发送给客户端。。。
好了,这里整个server组件的工作流程也就比较的清晰了,用一张图来总结吧:
(1)首先connector组件接收到数据
(2)调用server组件来处理数据,server组件根据route信息通过handleservice找到相应的handler以及对应的方法来处理
(3)再通过connector组件将返回的数据发送给客户端。。。