pomelo源码分析(二)

接着(一)所分析的代码

// app configure
app.configure('production|development', function() {
	// route configures
	app.route('chat', routeUtil.chat);

	// filter configures
	app.filter(pomelo.timeout());
});

根据开发环境是产品还是开发,调整服务器所使用的中间件,这里使用了路由器和过滤器的中间件,让我们进入函数来分析一下这些中间件到底做什么。

/**
 * Set the route function for the specified server type.
 *
 * Examples:
 *
 *  app.route('area', routeFunc);
 *
 *  var routeFunc = function(session, msg, app, cb) {
 *    // all request to area would be route to the first area server
 *    var areas = app.getServersByType('area');
 *    cb(null, areas[0].id);
 *  };
 *
 * @param  {String} serverType server type string
 * @param  {Function} routeFunc  route function. routeFunc(session, msg, app, cb)
 * @return {Object}     current application instance for chain invoking
 *
 * @memberOf Application
 */
Application.route = function(serverType, routeFunc) {
  var routes = this.get('__routes__');
  if(!routes) {
    routes = {};
    this.set('__routes__', routes);
  }
  routes[serverType] = routeFunc;
  return this;
};

route函数作用就是将 serverType 对应的功能函数写入routes的配置下,routefunc属于路由器的回调函数,route主要是记录路由器绑定的函数,接下来我们看看被绑定的函数routeUtil.chat

var exp = module.exports;
var dispatcher = require('./dispatcher');

exp.chat = function(session, msg, app, cb) {
	var chatServers = app.getServersByType('chat');

	if(!chatServers || chatServers.length === 0) {
		cb(new Error('can not find chat servers.'));
		return;
	}

	var res = dispatcher.dispatch(session.get('rid'), chatServers); //随机获取一个提供服务的服务器ID

	cb(null, res.id);
};

函数主要的功能在于 dispatcher.dispatch(session.get('rid'), chatServers); 这个函数主要的功能是随机获取一个提供服务的服务器ID,并将di返回给上层的函数

var crc = require('crc');

module.exports.dispatch = function(uid, connectors) {
    var index = Math.abs(crc.crc32(uid)) % connectors.length;
    return connectors[index];
};

函数通过crc库和rid来随机生成一个数字,通过数字来随机抽取一个服务器为这个url请求作出相应,路由器的功能分析完毕

过滤器

/**
 * add a filter to before and after filter
 *
 * @param {Object} filter provide before and after filter method. A filter should have two methods: before and after
 *
 * @memberOf Application
 */
Application.filter = function (filter) {
  this.before(filter);
  this.after(filter);
  return this;
};

过滤器要求filter对象至少包含两个方法,过滤前和过滤后。

/**
 * Add before filter.
 *
 * @param {Object|Function} bf before fileter, bf(msg, session, next)
 *
 * @memberOf Application
 */
Application.before = function (bf) {
  var befores = this.get('__befores__');
  if(!befores) {
    befores = [];
    this.set('__befores__', befores);
  }
  befores.push(bf);
  return this;
};

before函数主要作用把filter存放到 before内存里面,为以后调用做准备,after同理。

可以看出来,flter函数需要一个叫filter的对象,对象需要至少包含after和before两种方法。我们看一下我们的主函数到底传的是什么值

	// filter configures
	app.filter(pomelo.timeout());

pomelo.timeout() ,在webstrom的IDE环境里面,显示该函数并没有定义,而实际上,该函数已经定义了,它是利用pomelo被声明的时候,动态加载的,接下来我们重新看看pomelo这个模块函数是怎么定义的,方便我们找出pomelo.timeout这个函数方法。


/*!
 * Pomelo
 * Copyright(c) 2012 xiechengchao <[email protected]>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */
var fs = require('fs');
var path = require('path');
var application = require('./application');


/**
 * Expose `createApplication()`.
 *
 * @module
 */

var Pomelo = module.exports = {};

/**
 * Framework version.
 */

Pomelo.version = '0.1';

/**
 * auto loaded components
 */
Pomelo.components = {};

/**
 * auto loaded filters
 * @type {Object}
 */
Pomelo.filters = {};

var self = this;

/**
 * Create an pomelo application.
 *
 * @return {Application}
 * @memberOf Pomelo
 * @api public
 */
Pomelo.createApp = function (opts) {
	var app = application;
	app.init(opts);
	self.app = app;
	return app;
};

/**
 * Get application
 */
Object.defineProperty(Pomelo, 'app', {
	get:function () {
		return self.app;
	}
});

Pomelo.channelService = require('./common/service/channelService');
Pomelo.taskManager = require('./common/service/taskManager');

/**
 * Auto-load bundled components with getters.
 */
fs.readdirSync(__dirname + '/components').forEach(function (filename) {
	if (!/\.js$/.test(filename)) {
		return;
	}
	var name = path.basename(filename, '.js');

	function load() {
		return require('./components/' + name);  //寻找components下的js文件,并通过require加载到源码中
	}
	Pomelo.components.__defineGetter__(name, load);
	Pomelo.__defineGetter__(name, load);
});

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);  //寻找 fileter下的js文件,并通过require加载到源码中
	}
	Pomelo.filters.__defineGetter__(name, load);
	Pomelo.__defineGetter__(name, load);
});

源码当中,有几个函数是比较陌生的,需要拿出来分析一下

/**
 * Get application
 */
Object.defineProperty(Pomelo, 'app', {
	get:function () {
		return self.app;
	}
});

详细api介绍:http://www.cnblogs.com/rubylouvre/archive/2010/09/19/1831128.html

这里的调用目的,主要是当我们访问 Pomelo.app时,将会调用get函数,返回self.app。


fs.readdirSync(__dirname + '/components').forEach(function (filename) {
	if (!/\.js$/.test(filename)) {
		return;
	}
	var name = path.basename(filename, '.js');

	function load() {
		return require('./components/' + name);  //寻找components下的js文件,并通过require加载到源码中
	}
	Pomelo.components.__defineGetter__(name, load);
	Pomelo.__defineGetter__(name, load);
});

forEach遍历对应目录下js文件,并通过require加载到pomelo下

	Pomelo.components.__defineGetter__(name, load);
	Pomelo.__defineGetter__(name, load);

为了理解上面函数的意思,百度了一下相关的例子

Date.prototype.__defineGetter__('year', function() {return this.getFullYear();}); 
Date.prototype.__defineSetter__('year', function(y) {this.setFullYear(y)}); 

var now = new Date; 
alert(now.year); 
now.year = 2006; 
alert(now); 

相当于重载了 get的方法,将对象后面的属性作为参数传入到回调函数里面

在Pomelo下相当于调用timeout下的模块,意思如下:

Pomelo.timeout = function load() {
    return require('./filters/handler/' + name);
}

当声明Pomelo.timeout时候,相当于调用?filters/handler/下的 timout.js文件


pomelo/lib/filters/handler/timeout.js

/**
 * Filter for timeout.
 * Print a warn information when request timeout.
 */
var logger = require('pomelo-logger').getLogger(__filename);

var DEFAULT_TIMEOUT = 3000; 

module.exports = function(timeout) {
  return new Filter(timeout || DEFAULT_TIMEOUT);
};

var Filter = function(timeout) {
  this.timeout = timeout;  //过期时间
  this.timeouts = {};   //定时器容器
  this.curId = 0;  //定时器ID
};

Filter.prototype.before = function(msg, session, next) {
  this.curId++;  
  this.timeouts[this.curId] = setTimeout(function() {   //设置定时器,并将定时器的变量存到timeouts的容器里面
    logger.warn('request %j timeout.', msg.__route__);
  }, this.timeout);
  session.__timeout__ = this.curId; //session 等级定时器的ID
  next();
};

Filter.prototype.after = function(err, msg, session, resp, next) {
  var timeout = this.timeouts[session.__timeout__]; //去除定时器的ID

  if(timeout) {           
    clearTimeout(timeout);  //清空定时器
    delete this.timeouts[session.__timeout__];
  }

  next(err, msg);
};


发布了112 篇原创文章 · 获赞 37 · 访问量 68万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章