"use strict";
const logger = require('@sex-pomelo/sex-pomelo-logger').getLogger('pomelo', __filename);
/**
* Filter service.
* Register and fire before and after filters.
*
* @class
*/
let ServiceFilter = function() {
this.befores = []; // before filters
this.afters = []; // after filters
};
module.exports = ServiceFilter;
ServiceFilter.prototype.name = 'filter';
/**
* Add before filter into the filter chain.
*
* @param filter {Object|Function} filter instance or filter function.
*/
ServiceFilter.prototype.before = function(filter){
this.befores.push(filter);
};
/**
* Add after filter into the filter chain.
*
* @param filter {Object|Function} filter instance or filter function.
*/
ServiceFilter.prototype.after = function(filter){
this.afters.unshift(filter);
};
/**
* TODO: other insert method for filter? such as unshift
*/
/**
* Do the before filter.
* Fail over if any filter pass err parameter to the next function.
*
* @param msg {Object} clienet request msg
* @param session {Object} a session object for current request
* @param cb {Function} cb(err) callback function to invoke next chain node
*/
ServiceFilter.prototype.beforeFilter = function(msg, session, cb) {
let index = 0, self = this;
let next = function(err, resp, opts) {
if(err || index >= self.befores.length) {
cb(err, resp, opts);
return;
}
let handler = self.befores[index++];
if(typeof handler === 'function') {
handler(msg, session, next);
} else if(typeof handler.before === 'function') {
handler.before(msg, session, next);
} else {
logger.error('meet invalid before filter, handler or handler.before should be function.');
next(new Error('invalid before filter.'));
}
}; //end of next
next();
};
/**
* Do after filter chain.
* Give server a chance to do clean up jobs after request responsed.
* After filter can not change the request flow before.
* After filter should call the next callback to let the request pass to next after filter.
*
* @param err {Object} error object
* @param session {Object} session object for current request
* @param {Object} resp response object send to client
* @param cb {Function} cb(err) callback function to invoke next chain node
*/
ServiceFilter.prototype.afterFilter = function(err, msg, session, resp, cb) {
let index = 0, self = this;
function next(err) {
//if done
if(index >= self.afters.length) {
cb(err);
return;
}
let handler = self.afters[index++];
if(typeof handler === 'function') {
handler(err, msg, session, resp, next);
} else if(typeof handler.after === 'function') {
handler.after(err, msg, session, resp, next);
} else {
logger.error('meet invalid after filter, handler or handler.after should be function.');
next(new Error('invalid after filter.'));
}
} //end of next
next(err);
};