pomelo组就之server组件分析



在前面的一篇文章中知道了connector组件的作用,而且知道了,connector接收到数据之后,会调用server组件的handle方法来处理这些数据,那么这篇文章我们就来看看server组件究竟是怎么进行工作的吧。。。

首先我们来看看server组件的包装器的定义:

[javascript] view plain copy print ?
  1. /** 
  2.  * Component for server starup. 
  3.  */  
  4. var Server = require('../server/server');  
  5.   
  6. /** 
  7.  * Component factory function 
  8.  * 
  9.  * @param {Object} app  current application context 
  10.  * @return {Object}     component instance 
  11.  */  
  12. module.exports = function(app) {  
  13.   return new Component(app);  
  14. };  
  15.   
  16. /** 
  17.  * Server component class 
  18.  * 
  19.  * @param {Object} app  current application context 
  20.  */  
  21. var Component = function(app) {  
  22.   this.server = Server.create(app);  //用于创建真正的server组件  
  23. };  
  24.   
  25. Component.prototype.name = '__server__';  
  26.   
  27. /** 
  28.  * Component lifecycle callback 
  29.  * 
  30.  * @param {Function} cb 
  31.  * @return {Void} 
  32.  */  
  33. Component.prototype.start = function(cb) {   //启动  
  34.   this.server.start();  
  35.   process.nextTick(cb);  
  36. };  
  37.   
  38. /** 
  39.  * Component lifecycle function 
  40.  * 
  41.  * @param {Boolean}  force whether stop the component immediately 
  42.  * @param {Function}  cb 
  43.  * @return {Void} 
  44.  */  
  45. Component.prototype.stop = function(force, cb) {  
  46.   this.server.stop();  
  47.   process.nextTick(cb);  
  48. };  
  49.   
  50. /** 
  51.  * Proxy server.handle 
  52.  */  
  53. Component.prototype.handle = function(msg, session, cb) {  //调用server的hanlder来处理接收到的数据,用cb来处理返回的数据  
  54.   this.server.handle(msg, session, cb);  
  55. };  
/**
 * 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究竟是怎么定义的吧,首先来看看它的构造函数:
[javascript] view plain copy print ?
  1. module.exports.create = function(app) {  
  2.   return new Server(app);  
  3. };  
  4. //这个可以看成是server的构造函数吧  
  5. var Server = function (app) {  
  6.   this.app = app;  
  7.   this.filterService = null;  
  8.   this.handlerService = null;  
  9.   this.state = ST_INITED;  
  10. };  
  11.   
  12. var pro = Server.prototype;  
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部分,来看看先:
[javascript] view plain copy print ?
  1. pro.start = function() {  
  2.   if(this.state > ST_INITED) {  
  3.     return;  
  4.   }  
  5.   
  6.   this.filterService = initFilter(this.app);  //初始化filter函数  
  7.   this.handlerService = initHandler(this.app);  //初始化handler  
  8.   this.state = ST_STARTED;  
  9. };  
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是怎么进行初始化的。。。
[javascript] view plain copy print ?
  1. //创建handlerservice  
  2. var initHandler = function(app) {  
  3.   return new HandlerService(app, loadHandlers(app));  
  4. };  
//创建handlerservice
var initHandler = function(app) {
  return new HandlerService(app, loadHandlers(app));
};
好吧,其实这里创建的是一个handlerservice,在创建它的同时,还要进行handler的load,来看看handler是怎么load的吧:
[javascript] view plain copy print ?
  1.  //为当前的server加载它的handler  
  2. var loadHandlers = function(app) {  
  3.   var p = pathUtil.getHandlerPath(app.getBase(), app.getServerType());  //用于根据server的类型来加载相应的handler  
  4.   if(p) {  
  5.     return Loader.load(p, app);  //加载handler  
  6.   }  
  7. };  
 //为当前的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是怎么定义的吧,先来看看它的构造函数:
[javascript] view plain copy print ?
  1. var Service = function(app, handlers) {  
  2.   this.app = app;  
  3.   this.handlers = handlers || {};  
  4. };  
var Service = function(app, handlers) {
  this.app = app;
  this.handlers = handlers || {};
};
很简单吧,无非就是保存一下app和handlers。。。


好了,那么接下来来看看server组件处理数据的流程吧,先来看最外面的server包装器它的handle方法:

[javascript] view plain copy print ?
  1. Component.prototype.handle = function(msg, session, cb) {  //调用server的hanlder来处理接收到的数据,用cb来处理返回的数据  
  2.   this.server.handle(msg, session, cb);  
  3. };  
Component.prototype.handle = function(msg, session, cb) {  //调用server的hanlder来处理接收到的数据,用cb来处理返回的数据
  this.server.handle(msg, session, cb);
};
没什么意思,不过这里需要说明的是,cb回调函数是在connector里面传过来的,handler处理完成后,可以调用cb将数据返回给客户端。。。。。以后会看到的。。

好了,接下来来深入内部看看吧:

[javascript] view plain copy print ?
  1.  //调用handler来处理信息  
  2. pro.handle = function(msg, session, cb) {  
  3.   if(this.state !== ST_STARTED) {  
  4.     cb(new Error('server not started'));  
  5.     return;  
  6.   }  
  7.   
  8.   var routeRecord = parseRoute(msg.route);  //用于解析route参数  
  9.   if(!routeRecord) {  
  10.     cb(new Error('meet unknown route message %j', msg.route));  
  11.     return;  
  12.   }  
  13.   
  14.   if(this.app.getServerType() !== routeRecord.serverType) {  //判断route的路径是否是到当前的服务器  
  15.     doForward(this.app, msg, session, routeRecord, cb);  //如果类型不符的话,那么用符合的服务器来处理  
  16.   } else {  
  17.     doHandle(this, msg, session, routeRecord, cb);  //符合,那么用当前的handler来处理  
  18.   }  
  19. };  
 //调用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进行处理:
[javascript] view plain copy print ?
  1. //这里调用用户定义的handler来处理数据  
  2. var doHandle = function(server, msg, session, routeRecord, cb) {  
  3.   var originMsg = msg;  
  4.   msg = msg.body || {};  
  5.   msg.__route__ = originMsg.route;  //相当于是保存route数据  
  6.   
  7.   var self = server;  
  8.   
  9.   var handle = function(err, resp) {  
  10.     if(err) {  
  11.       // error from before filter  
  12.       handleError(self, err, msg, session, resp, function(err, resp) {  
  13.         response(self, err, msg, session, resp, cb);  
  14.       });  
  15.       return;  
  16.     }  
  17. //调用handler进行处理  
  18.     self.handlerService.handle(routeRecord, msg, session, function(err, resp) {  
  19.       if(err) {  
  20.         //error from handler  
  21.         handleError(self, err, msg, session, resp, function(err, resp) {  
  22.           response(self, err, msg, session, resp, cb);    
  23.         });  
  24.         return;  
  25.       }  
  26.   
  27.       response(self, err, msg, session, resp, cb);  //相当于是向客户端返回信息  
  28.     });  
  29.   };  //end of handle  
  30.   
  31.   beforeFilter(server, msg, session, handle);  
  32. };  
//这里调用用户定义的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方法吧:
[javascript] view plain copy print ?
  1. Service.prototype.handle = function(routeRecord, msg, session, cb){  
  2.   // the request should be processed by current server  
  3.   var handler = getHandler(this.handlers, routeRecord);  //根据handdler的名字获取handler  
  4.   if(!handler) {  
  5.     logger.error('[handleManager]: fail to find handler for %j', msg.__route__);  
  6.     cb(new Error('fail to find handler for ' + msg.__route__));  
  7.     return;  
  8.   }  
  9.   var start = Date.now();  
  10.   
  11.   handler[routeRecord.method](msg, session, function(err,resp){  //相当于是根据method的名字来执行相应的方法,传入的额函数就是handler里的next参数,用于将返回的数据发送给客户端  
  12.     var log = {  
  13.       route : msg.__route__,  
  14.       args : msg,  
  15.       time : utils.format(new Date(start)),  
  16.       timeUsed : new Date() - start  
  17.     };  
  18.     forward_logger.info(JSON.stringify(log));  
  19.     cb(err,resp);  
  20.   });  
  21.   return;  
  22. };  
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组件将返回的数据发送给客户端。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值