"use strict";

/**
 * Filter to keep request sequence.
 * @access private
 */
const logger = require('@sex-pomelo/sex-pomelo-logger').getLogger('pomelo', __filename);
const taskManager = require('../../common/manager/taskManager');

module.exports = function(timeout) {
  return new FilterHandlerSerial(timeout);
};

/**
 * This filter is used to do serialization of user requests, and it can make requestes from 
 * a certain session to be handled one by one in the same order as their being sent. It uses 
 * a serial taskManager, when a request comes in, in the beforeFilter, it will put the request into taskManager with session.id as key,
 * taskManager maintains a map <SessionId, taskQueue> for all session.
 * In the corresponding afterFilter, if there is a pending request in its taskManager,
 * it will be handled. As so, it implements the task serialization.
 * <br/>
 * 这个filter是用来对用户请求做串行化的,可以使得用户的请求只有在第一个请求被处理完后,才会处理第二个请求。
 * serial中使用了一个taskManager,当用户请求到来时,在beforeFilter中,将用户的请求放到taskManager中,
 * taskManager中维护着一个task队列。在对应的afterFilter中,如果taskManager还有未处理的请求,将会处理其请求,
 * 即在一个请求的afterFilter里启动在taskManager中还没处理的下一个请求,这样就实现了请求的序列化。
 * 
 * @class
 * @implements {Filter}
 */
let FilterHandlerSerial = function(timeout) {
  this.timeout = timeout;
};

/**
 * request serialization after filter
 */
FilterHandlerSerial.prototype.before = function(msg, session, next) {
  taskManager.addTask(session.id, function(task) {
    session.__serialTask__ = task;
    next();
  }, function() {
    logger.error('[serial filter] msg timeout, msg:' + JSON.stringify(msg));
  }, this.timeout);
};

/**
 * request serialization after filter
 */
FilterHandlerSerial.prototype.after = function(err, msg, session, resp, next) {
  let task = session.__serialTask__;
  if(task) {
    if(!task.done() && !err) {
      err = new Error('task time out. msg:' + JSON.stringify(msg));
    }
  }
  next(err);
};