"use strict";
const fs = require('fs');
const utils = require('../../util/utils');
const Loader = require('pomelo-loader');
const pathUtil = require('../../util/pathUtil');
const logger = require('@sex-pomelo/sex-pomelo-logger').getLogger('pomelo', __filename);
const forwardLogger = require('@sex-pomelo/sex-pomelo-logger').getLogger('forward-log', __filename);
const Application = require('../../application');
class HandlerService{
/**
* Handler service.
* Dispatch request to the relactive handler.
*
* @param {Application} app current application context
* @param {object} opts
*/
constructor(app, opts){
this.name = 'handler';
this.app = app;
this.handlerMap = {};
if(!!opts.reloadHandlers) {
watchHandlers(app, this.handlerMap);
}
this.enableForwardLog = opts.enableForwardLog || false;
let autoStart = app.get('yz_autoStartHandler');//lifecycle::beforeStartup yz_autoStartHandler
if( autoStart ===true){
loadHandlers(this.app, app.getServerType(),this.handlerMap);
}
}
/**
* Handler the request.
*/
handle(routeRecord, msg, session, cb) {
// the request should be processed by current server
let handler = this.getHandler(routeRecord);
if(!handler) {
logger.error('[handleManager]: fail to find handler for %j', msg.__route__);
utils.invokeCallback(cb, new Error('fail to find handler for ' + msg.__route__));
return;
}
let start = Date.now();
let self = this;
let callback = function(err, resp, opts) {
if(self.enableForwardLog) {
let log = {
route : msg.__route__,
args : msg,
time : utils.format(new Date(start)),
timeUsed : new Date() - start
};
forwardLogger.info(JSON.stringify(log));
}
// resp = getResp(arguments);
utils.invokeCallback(cb, err, resp, opts);
}
let method = routeRecord.method;
if(!Array.isArray(msg)) {
handler[method](msg, session, callback);
} else {
msg.push(session);
msg.push(callback);
handler[method].apply(handler, msg);
}
return;
}
/**
* Get handler instance by routeRecord.
*
* @param {Object} handlers handler map
* @param {Object} routeRecord route record parsed from route string
* @return {Object} handler instance if any matchs or null for match fail
*/
getHandler(routeRecord) {
let serverType = routeRecord.serverType;
if(!this.handlerMap[serverType]) {
loadHandlers(this.app, serverType, this.handlerMap);
}
let handlers = this.handlerMap[serverType] || {};
let handler = handlers[routeRecord.handler];
if(!handler) {
logger.warn('could not find handler for routeRecord: %j', routeRecord);
return null;
}
if(typeof handler[routeRecord.method] !== 'function') {
logger.warn('could not find the method %s in handler: %s', routeRecord.method, routeRecord.handler);
return null;
}
return handler;
};
}
module.exports = HandlerService;
/**
* Load handlers from current application
* @access private
*/
let loadHandlers = function(app, serverType, handlerMap) {
let p = pathUtil.getHandlerPath(app.getBase(), serverType);
if(p) {
handlerMap[serverType] = Loader.load(p, app);
}
};
let watchHandlers = function(app, handlerMap) {
let p = pathUtil.getHandlerPath(app.getBase(), app.serverType);
if (!!p){
fs.watch(p, function(event, name) {
if(event === 'change') {
handlerMap[app.serverType] = Loader.load(p, app);
}
});
}
};
let getResp = function(args) {
let len = args.length;
if(len == 1) {
return [];
}
if(len == 2) {
return [args[1]];
}
if(len == 3) {
return [args[1], args[2]];
}
if(len == 4) {
return [args[1], args[2], args[3]];
}
let r = new Array(len);
for (let i = 1; i < len; i++) {
r[i] = args[i];
}
return r;
}