接着(一)所分析的代码
// 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; };
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); };
var crc = require('crc'); module.exports.dispatch = function(uid, connectors) { var index = Math.abs(crc.crc32(uid)) % connectors.length; return connectors[index]; };
过滤器
/** * 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; };
/** * 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; };
可以看出来,flter函数需要一个叫filter的对象,对象需要至少包含after和before两种方法。我们看一下我们的主函数到底传的是什么值
// filter configures app.filter(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; } });
这里的调用目的,主要是当我们访问 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); });
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/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); };