|
|
var util = require('util');
|
|
|
var Emitter=require('events');
|
|
|
var Emitter = require('events');
|
|
|
var Request = require('request');
|
|
|
var async=require('async');
|
|
|
var async = require('async');
|
|
|
/*接口*/
|
|
|
var _ = require('lodash');
|
|
|
|
|
|
var Utils=require('./Utils');
|
|
|
var Utils = require('./Utils');
|
|
|
|
|
|
|
|
|
var Interfacer=function(config,app){
|
|
|
this.config=config;
|
|
|
this.CONSTS=app.get("Register");
|
|
|
this.config.domain=this.config.domain||app.get("Register").domain;
|
|
|
this.apis={};
|
|
|
Emitter.call(this);
|
|
|
var Interfacer = function (config, app) {
|
|
|
this.config = config;
|
|
|
this.CONSTS = app.get("Register");
|
|
|
this.config.domain = this.config.domain || app.get("Register").domain;
|
|
|
this.apis = {};
|
|
|
Emitter.call(this);
|
|
|
};
|
|
|
|
|
|
util.inherits(Interfacer,Emitter);
|
|
|
util.inherits(Interfacer, Emitter);
|
|
|
|
|
|
Interfacer.prototype.register = function(mos) {
|
|
|
var me=this,name=mos.namespace;
|
|
|
if(!name){
|
|
|
console.info(" Interfacer name can not empty");
|
|
|
}
|
|
|
for(var key in mos.apis){
|
|
|
var name_key=name+"_"+key;
|
|
|
if(me.isExisted(name_key)){
|
|
|
console.info("can not add repeat Interfacer key,please checkout");
|
|
|
}
|
|
|
/*需要进行验证判断*/
|
|
|
me.apis[name_key]=mos.apis[key];
|
|
|
}
|
|
|
Interfacer.prototype.register = function (mos) {
|
|
|
var me = this, name = mos.namespace;
|
|
|
if (!name) {
|
|
|
console.info(" Interfacer name can not empty");
|
|
|
}
|
|
|
for (var key in mos.apis) {
|
|
|
var name_key = name + "_" + key;
|
|
|
if (me.isExisted(name_key)) {
|
|
|
console.info("can not add repeat Interfacer key,please checkout");
|
|
|
}
|
|
|
/*需要进行验证判断*/
|
|
|
me.apis[name_key] = mos.apis[key];
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Interfacer.prototype.isExisted=function(key){
|
|
|
return !!this.apis[key];
|
|
|
Interfacer.prototype.isExisted = function (key) {
|
|
|
return !!this.apis[key];
|
|
|
};
|
|
|
Interfacer.prototype.getInterfacerByNameSpace = function (namespace) {
|
|
|
var me = this;
|
|
|
if (!namespace) return {};
|
|
|
var apis = {}, len = namespace.length;
|
|
|
for (var key in me.apis) {
|
|
|
if (key.slice(0, len + 1) === namespace + "_") {
|
|
|
var name = key.slice(len + 1);
|
|
|
if (typeof me.apis[key] !== "function") {
|
|
|
apis[name] = me.apis[key];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return apis;
|
|
|
}
|
|
|
|
|
|
function __getArgs(str) {
|
|
|
var arr = str.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].split(',');
|
|
|
return (arr.length == 1 && arr[0] == "")?[]:arr;
|
|
|
}
|
|
|
|
|
|
function __requestApi(config, apiOpt, req, callback){
|
|
|
var me=this;
|
|
|
function __requestApi(config, apiOpt, req, callback) {
|
|
|
var me = this;
|
|
|
if (typeof apiOpt == "function") {
|
|
|
return apiOpt.call(0, req, function (err, result) {
|
|
|
req._yoheaders = req._yoheaders;
|
|
|
return callback(null, result);
|
|
|
});
|
|
|
}
|
|
|
var method = apiOpt.method || "POST";
|
|
|
var data={};
|
|
|
if(apiOpt.params&&(_.isArray(apiOpt.params)||_.isPlainObject(apiOpt.params))){
|
|
|
if(_.isArray(apiOpt.params)){
|
|
|
apiOpt.params.forEach(function(param){
|
|
|
var name=param.name;
|
|
|
if(req.param(name)){
|
|
|
if(param.type.toUpperCase()=="NUMBER"){
|
|
|
data[name]=Number(req.param(name));
|
|
|
}else{
|
|
|
data[name]=String(req.param(name));
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}else
|
|
|
if(_.isPlainObject(apiOpt.params)){
|
|
|
for(var name in apiOpt.params){
|
|
|
var param=apiOpt.params[name];
|
|
|
if(param.default){
|
|
|
data[name]=param.type(param.default);
|
|
|
}
|
|
|
if(req.param(name)){
|
|
|
data[name]=param.type(req.param(name));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var options={
|
|
|
url: Utils.template((apiOpt.domain||config.domain)+apiOpt.url,me.CONSTS),
|
|
|
method:apiOpt.method,
|
|
|
//数据组装
|
|
|
qs: method.toUpperCase()=="GET"?data:undefined,
|
|
|
// form:apiOpt.method.toUpperCase()=="GET"?undefined:data//,
|
|
|
body: method.toUpperCase()=="GET"?undefined:JSON.stringify(data),
|
|
|
|
|
|
var args = __getArgs(apiOpt), o = {};
|
|
|
if (args.length > 2) {
|
|
|
args.slice(2).map(function (namespace) {
|
|
|
namespace = _.trim(namespace);
|
|
|
o[namespace] = {};
|
|
|
var apis = me.getInterfacerByNameSpace(namespace);
|
|
|
for (var action in apis) {
|
|
|
o[namespace][action] = (function (api, config, consts) {
|
|
|
var intermo = new Interfacer.create(api);
|
|
|
return function () {
|
|
|
var args = [].slice.call(arguments, 0), params = {};
|
|
|
intermo.apiOpt = api;
|
|
|
intermo.config = {
|
|
|
config: config,
|
|
|
consts: consts
|
|
|
};
|
|
|
|
|
|
if (args.length === 1 && _.isPlainObject(args[0])) {
|
|
|
intermo.req.param(args[0]);
|
|
|
} else {
|
|
|
api.params = api.params || {};
|
|
|
var os = Object.keys(api.params);
|
|
|
args.forEach(function (value, i) {
|
|
|
params[os[i]] = value;
|
|
|
});
|
|
|
intermo.req.param(params);
|
|
|
}
|
|
|
if (!this.queue) {
|
|
|
this.queue = [];
|
|
|
}
|
|
|
this.queue.push(intermo);
|
|
|
this.__proto__ = new queue();
|
|
|
return this;
|
|
|
};
|
|
|
})(apis[action], config, me.CONSTS);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
var fns = [];
|
|
|
for (var i in o) {
|
|
|
fns.push(o[i]);
|
|
|
}
|
|
|
//return apiOpt.call(0, req, function (err, result) {
|
|
|
// req._yoheaders = req._yoheaders;
|
|
|
// return callback(null, result);
|
|
|
//});
|
|
|
return apiOpt.apply(0, [req, function (err, result) {
|
|
|
req._yoheaders = req._yoheaders;
|
|
|
return callback(null, result);
|
|
|
}].concat(fns));
|
|
|
}
|
|
|
|
|
|
var options = __requestOption(req, apiOpt, config, me.CONSTS);
|
|
|
|
|
|
Request(options, function (error, response, body) {
|
|
|
var _err_ = new Error();
|
|
|
if (error) {
|
|
|
console.info("Error [request]:" + options.title);
|
|
|
console.error(error);
|
|
|
return callback(error, null);
|
|
|
}
|
|
|
try {
|
|
|
if (response && response.statusCode === 200) {
|
|
|
var obj = JSON.parse(body)
|
|
|
if (!(typeof obj == "object")) {
|
|
|
_err_.message = "Error[json parse@" + options.title + "]:" + body;
|
|
|
console.info(_err_.message);
|
|
|
console.error(err);
|
|
|
return callback(_err_, null);
|
|
|
}
|
|
|
} else {
|
|
|
_err_.message = "Error[response state @" + options.title + "]:" + response;
|
|
|
console.info(_err_.message);
|
|
|
console.error(err);
|
|
|
return callback(_err_, null);
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
|
|
console.info("Error[response to json @" + options.title + "]");
|
|
|
console.info(response);
|
|
|
console.error(err);
|
|
|
return callback(err, null);
|
|
|
}
|
|
|
return callback(null, JSON.parse(body));
|
|
|
});
|
|
|
};
|
|
|
|
|
|
function __requestOption(req, apiOpt, config, consts) {
|
|
|
var method = (apiOpt.method || "POST").toLocaleUpperCase();
|
|
|
var data = {};
|
|
|
if (apiOpt.params && (_.isArray(apiOpt.params) || _.isPlainObject(apiOpt.params))) {
|
|
|
if (_.isArray(apiOpt.params)) {
|
|
|
//兼容 yo之前的模式 后期废弃
|
|
|
apiOpt.params.forEach(function (param) {
|
|
|
var name = param.name;
|
|
|
if (req.param(name)) {
|
|
|
if (param.type.toUpperCase() == "NUMBER") {
|
|
|
data[name] = Number(req.param(name));
|
|
|
} else {
|
|
|
data[name] = String(req.param(name));
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
} else
|
|
|
if (_.isPlainObject(apiOpt.params)) {
|
|
|
for (var name in apiOpt.params) {
|
|
|
if (req.param("@" + name)) {
|
|
|
continue;
|
|
|
}
|
|
|
var param = apiOpt.params[name];
|
|
|
if (param.default) {
|
|
|
data[name] = param.type(param.default);
|
|
|
}
|
|
|
if (req.param(name)) {
|
|
|
data[name] = param.type(req.param(name));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var options = { method: method };
|
|
|
options.title = apiOpt.title || '';
|
|
|
options.outobj = apiOpt.outobj || '';
|
|
|
if (options.method == "GET") {
|
|
|
apiOpt.query = true;
|
|
|
}
|
|
|
|
|
|
headers: apiOpt.headers||{
|
|
|
'Content-Type' : 'application/json'
|
|
|
}
|
|
|
};
|
|
|
if (req._yoheaders) {
|
|
|
options.headers= _.merge(options.headers, req._yoheaders);
|
|
|
if (/^https{0,1}:\/\//g.test(apiOpt.url)) {
|
|
|
options.url = apiOpt.url;
|
|
|
} else {
|
|
|
options.url = (apiOpt.domain || config.domain) + apiOpt.url;
|
|
|
}
|
|
|
if (/\{\{.*\}\}/.test(options.url)) {
|
|
|
var _qs = {};
|
|
|
if (apiOpt.query) {
|
|
|
_qs = data;
|
|
|
}
|
|
|
var a = _.merge(consts, _qs);
|
|
|
options.url=Utils.template(options.url, a);
|
|
|
}
|
|
|
|
|
|
if (apiOpt.form) {
|
|
|
if (typeof apiOpt.form === "string") {
|
|
|
options.form = Utils.template(apiOpt.form, data);
|
|
|
} else if (_.isPlainObject(apiOpt.form)) {
|
|
|
options.form = {};
|
|
|
for (var i in apiOpt.form) {
|
|
|
options.form[i] = Utils.template(apiOpt.form[i], data)
|
|
|
}
|
|
|
}
|
|
|
options.headers = {
|
|
|
'Content-Type' : 'application/x-www-form-urlencoded'
|
|
|
}
|
|
|
} if (apiOpt.query) {
|
|
|
//不做任何事
|
|
|
} else {
|
|
|
options.body = JSON.stringify(data);
|
|
|
options.headers = {
|
|
|
'Content-Type' : 'application/json'
|
|
|
}
|
|
|
}
|
|
|
if (apiOpt.headers && _.isPlainObject(apiOpt.headers)) {
|
|
|
options.headers = {};
|
|
|
for (var name in apiOpt.headers) {
|
|
|
var param = apiOpt.headers[name];
|
|
|
if (req.param("@" + name)) {
|
|
|
if (param.default) {
|
|
|
options.headers[name] = param.type(param.default);
|
|
|
}
|
|
|
if (req.param("@" + name)) {
|
|
|
options.headers[name] = param.type(req.param("@" + name));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (req._yoheaders) {
|
|
|
options.headers = _.merge(options.headers, req._yoheaders);
|
|
|
}
|
|
|
console.log("*************************************");
|
|
|
console.log("Http", options.url, data, options.headers);
|
|
|
console.log("*************************************");
|
|
|
console.log("Http",options.url,data,options.headers);
|
|
|
console.log("*************************************");
|
|
|
return options;
|
|
|
}
|
|
|
|
|
|
Request(options,function(error, response, body){
|
|
|
var _err_=new Error();
|
|
|
if(error){
|
|
|
console.info("Request 请求错误");
|
|
|
console.error(error);
|
|
|
return callback(error,null);
|
|
|
}
|
|
|
try{
|
|
|
if(response && response.statusCode === 200){
|
|
|
var obj=JSON.parse(body)
|
|
|
if(!(typeof obj=="object")){
|
|
|
_err_.message="Error[json parse@"+apiOpt.title+"]:"+body;
|
|
|
return callback(_err_,null);
|
|
|
}
|
|
|
}else{
|
|
|
_err_.message="Error[response@"+apiOpt.title+"]:"+response.statusCode;
|
|
|
return callback(_err_,null);
|
|
|
}
|
|
|
|
|
|
}catch(err){
|
|
|
console.info("Request 内容转化JSON错误@"+apiOpt.title+"");
|
|
|
console.info(response);
|
|
|
console.error(err);
|
|
|
return callback(err,null);
|
|
|
}
|
|
|
return callback(null,JSON.parse(body));
|
|
|
});
|
|
|
};
|
|
|
/*
|
|
|
* {mos} 接口key 数组 比如[key1,key2] 后面可能要兼容字符串 比如 传key1
|
|
|
*/
|
|
|
Interfacer.prototype.require=function(mos,req,res,cb){
|
|
|
var me=this,funcs=[],names=[],errName=[];
|
|
|
|
|
|
mos.forEach(function(name){
|
|
|
|
|
|
if(me.apis.hasOwnProperty(name)){
|
|
|
names.push(name);
|
|
|
if(me.config.mock){
|
|
|
funcs.push(me.apis[name].output);
|
|
|
}else{
|
|
|
funcs.push(function(callback){
|
|
|
__requestApi.call(me,me.config,me.apis[name],req,callback);
|
|
|
});
|
|
|
}
|
|
|
}else{
|
|
|
errName.push(name);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
Interfacer.prototype.require = function (mos, req, res, cb) {
|
|
|
var me = this, funcs = [], names = [], errName = [];
|
|
|
|
|
|
mos.forEach(function (name) {
|
|
|
|
|
|
if (me.apis.hasOwnProperty(name)) {
|
|
|
names.push(name);
|
|
|
if (me.config.mock) {
|
|
|
funcs.push(me.apis[name].output);
|
|
|
} else {
|
|
|
funcs.push(function (callback) {
|
|
|
__requestApi.call(me, me.config, me.apis[name], req, callback);
|
|
|
});
|
|
|
}
|
|
|
} else {
|
|
|
errName.push(name);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
if (funcs.length != mos.length) {
|
|
|
var err = new Error();
|
|
|
err.message = "某个"+errName.join("->")+" 可能不存在!";
|
|
|
err.message = "某个" + errName.join("->") + " 可能不存在!";
|
|
|
cb(err, funcs, names);
|
|
|
return;
|
|
|
}
|
|
|
if(me.config.mock){
|
|
|
cb(null,funcs,names);
|
|
|
return;
|
|
|
}
|
|
|
async.parallel(funcs, function(err, results){
|
|
|
if(err){
|
|
|
console.info("Async Error");
|
|
|
console.error(err);
|
|
|
console.error(results);
|
|
|
return cb(err,results,names);
|
|
|
}
|
|
|
console.log(names);
|
|
|
return;
|
|
|
}
|
|
|
if (me.config.mock) {
|
|
|
cb(null, funcs, names);
|
|
|
return;
|
|
|
}
|
|
|
async.parallel(funcs, function (err, results) {
|
|
|
if (err) {
|
|
|
console.info("Async Error");
|
|
|
console.error(err);
|
|
|
console.error(results);
|
|
|
return cb(err, results, names);
|
|
|
}
|
|
|
return cb(null, results, names);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
Interfacer.create = function (apis) {
|
|
|
return {
|
|
|
req: {
|
|
|
__params__: null,
|
|
|
param: function (value) {
|
|
|
if (typeof value == "object") {
|
|
|
this.__params__ = value;
|
|
|
} else {
|
|
|
return this.__params__[value];
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
apiOpt: null,
|
|
|
config: {},
|
|
|
|
|
|
error: function () {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
function queue() { }
|
|
|
queue.prototype = {
|
|
|
done: function (success, fail) {
|
|
|
var that = this;
|
|
|
if (typeof success !== 'function') return;
|
|
|
var len = that.queue.length, watchlen = { len: len };
|
|
|
var args = new Array(3);
|
|
|
var wlen=Object.defineProperty({}, 'len', {
|
|
|
value: len,
|
|
|
writable: true,
|
|
|
enumerable: false,
|
|
|
configurable: true
|
|
|
});
|
|
|
for (var i = 0; i < len; i++) {
|
|
|
(function (queue,args) {
|
|
|
var options = __requestOption(queue.req, queue.apiOpt, queue.config.config, queue.config.consts);
|
|
|
__sendRequest(options, success, fail, wlen, i,args);
|
|
|
})(this.queue[i],args);
|
|
|
}
|
|
|
that.queue = null;
|
|
|
//var options = __requestOption(this.req, this.apiOpt);
|
|
|
//this.__sendRequest(options, success, fail);
|
|
|
return this;
|
|
|
},
|
|
|
|
|
|
}
|
|
|
function __sendRequest(options, success, fail,wlen,i,args) {
|
|
|
Request(options, function (error, response, body) {
|
|
|
var _err_ = new Error(), obj;
|
|
|
if (error) {
|
|
|
console.info("Error [request]:" + options.title);
|
|
|
console.error(error);
|
|
|
fail && fail(error);
|
|
|
return;
|
|
|
}
|
|
|
try {
|
|
|
if (response && response.statusCode === 200) {
|
|
|
if (!options.outobj) {
|
|
|
obj = JSON.parse(body)
|
|
|
if (!(typeof obj == "object")) {
|
|
|
_err_.message = "Error[json parse@" + options.title + "]:" + body;
|
|
|
console.info(_err_.message);
|
|
|
console.error(err);
|
|
|
fail && fail(_err_);
|
|
|
return;
|
|
|
}
|
|
|
} else {
|
|
|
obj = options.outobj.toLocaleUpperCase().indexOf("BODY")>-1?body:response;
|
|
|
}
|
|
|
} else {
|
|
|
_err_.message = "Error[response state @" + options.title + "]:" + response;
|
|
|
console.info(_err_.message);
|
|
|
console.error(err);
|
|
|
fail && fail(_err_);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
|
|
console.info("Error[response to json @" + options.title + "]");
|
|
|
console.info(response);
|
|
|
console.error(err);
|
|
|
fail && fail(err);
|
|
|
return;
|
|
|
}
|
|
|
args[i]=obj;
|
|
|
wlen.len--;
|
|
|
if (!wlen.len) {
|
|
|
success && success.apply(0, args)
|
|
|
}
|
|
|
return;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
module.exports= Interfacer; |
|
|
\ No newline at end of file |
|
|
module.exports = Interfacer; |
|
|
\ No newline at end of file |
...
|
...
|
|