tar-api.js 5.98 KB
/*
* @Author: Targaryen
* @Date:   2016-05-23 15:27:46
* @Last Modified by:   Targaryen
* @Last Modified time: 2016-05-24 14:33:37
*/

'use strict';

const rp = require('request-promise');
const qs = require('querystring');
const md5 = require('md5');
const _ = require('lodash');
const log = require('./logger');
const cache = require('./cache');
const Timer = require('./timer');
const config = require('../config/common');
const api = config.domains.api;
const serviceApi = config.domains.service;
const searchApi = config.domains.search;


let ApiUrl;

class TARAPI {

    constructor() {
        ApiUrl = api;
    }

    /**
     * 获取请求 ID
     */
    _getReqId(options) {
        return md5(`${options.url}?${qs.stringify(options.qs || options.form)}`);
    }

    /**
     * 调用接口
     */
    _requestFromAPI(options, cacheOption, reqId) {
        let timer = new Timer();

        timer.put('getApi');// 统计时间开始

        log.info(`get api: ${options.url}?${qs.stringify(options.qs)}`);
        return rp(options).then((result) => {
            let duration = timer.put('getApi');// 统计时间结束

            log.info(`get api success: use: ${duration}ms`);
            if (config.useCache && cacheOption) {
                reqId = reqId || this._getReqId(options);

                // 数据校验无误,写缓存, 否则返回 Slave 缓存服务器的数据
                if (result && result.code) {
                    let cacheTime = _.isNumber(cacheOption) ? cacheOption : 60;

                    cache.set(`apiCache:${reqId}`, result, cacheTime);
                    cache.setSlave(`apiCache:${reqId}`, result, cacheTime);
                } else {
                    return this._requestFromCache(options, true);
                }
            }
            return result;
        }).catch((error)=>{
            let duration = timer.put('getApi');// 统计时间结束

            log.error(`get api fail: use: ${duration}ms, statusCode: ${error.statusCode}, error: ${error.message}`);

            // 使用缓存的时候,读取二级缓存
            if (config.useCache) {
                return this._requestFromCache(options, true);
            }
            return Promise.reject({
                error: '接口调用失败'
            });
        });
    }

    /**
     * 读取缓存
     * @param  {[object]} options
     * @param  {[boolean]} slave true: 读取二级缓存
     * @return {[type]}
     */
    _requestFromCache(options, slave) {
        let reqId = this._getReqId(options);
        let getCache = slave ? cache.getFromSlave : cache.get;

        log.info(`get cache: ${reqId}, url: ${options.url}?${qs.stringify(options.qs)}`);
        return getCache(`apiCache:${reqId}`).then((result) => {
            if (!_.isNil(result)) {
                try {
                    result = JSON.parse(result);
                } finally {
                    log.info(slave ? 'get slave cache success' : 'get master cache success');
                    return result;
                }
            }

            if (!slave) {
                return this._requestFromAPI(options, true, reqId);
            }
        }).catch(() => {
            log.error(slave ? 'get slave cache fail' : 'get master cache fail');
            if (!slave) {
                return this._requestFromAPI(options, true, reqId);
            }
        });
    }

    /**
     * 使用 get 请求获取接口
     * @param  {[string]} url
     * @param  {[object]} data
     * @param  {[bool or number]} cacheOption 使用数字时,数字表示缓存时间
     * @return {[type]}
     */
    get(url, data, cacheOption) {
        let options = {
            url: `${ApiUrl}${url}`,
            qs: data,
            json: true,
            timeout: 3000
        };

        // 从缓存获取数据
        if (config.useCache && cacheOption) {
            return this._requestFromCache(options);
        }

        return this._requestFromAPI(options, cacheOption);
    }

    /**
     * 调用活动列表
     * @param  {[string]} url
     * @param  {[object]} data
     * @param  {[bool or number]} cacheOption 使用数字时,数字表示缓存时间
     * @return {[type]}
     */
    getActivity(url, data, cacheOption) {
        let options = {
            url: `http://testapi.yoho.cn:28078/gateway${url}`,
            qs: data,
            json: true,
            timeout: 3000
        };

        // 从缓存获取数据
        if (config.useCache && cacheOption) {
            return this._requestFromCache(options);
        }

        return this._requestFromAPI(options, cacheOption);
    }


    /**
     * 调用 banner
     * @param  {[string]} url
     * @param  {[object]} data
     * @param  {[bool or number]} cacheOption 使用数字时,数字表示缓存时间
     * @return {[type]}
     */
    getBanner(url, data, cacheOption) {
        let options = {
            url: 'http://service.yoho.cn/operations/api/v5/resource/get',
            qs: data,
            json: true,
            timeout: 3000
        };

        // 从缓存获取数据
        if (config.useCache && cacheOption) {
            return this._requestFromCache(options);
        }

        return this._requestFromAPI(options, cacheOption);
    }


    /**
     * post
     * @param url String
     * @param data Obejct
     */
    post(url, data) {
        let options = {
            url: `${ApiUrl}${url}`,
            form: data,
            method: 'post',
            json: true,
            timeout: 3000
        };

        return this._requestFromAPI(options);
    }

    all(list) {
        if (_.isArray(list)) {
            return Promise.all(list);
        }
        throw Error('the parameters of api all method should be Array!');
    }
}

class ServiceAPI extends TARAPI {
    constructor() {
        super();
        ApiUrl = serviceApi;
    }
}

class SearchAPI extends TARAPI {
    constructor() {
        super();
        ApiUrl = searchApi;
    }
}

exports.TARAPI = TARAPI;
exports.ServiceAPI = ServiceAPI;
exports.SearchAPI = SearchAPI;