在前面的一篇文章中知道了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组件将返回的数据发送给客户端。。。