"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.act = exports.add = exports.init = void 0;
const _ = require("lodash");
const path = require("path");
const rp = require("request-promise");
const fastify = require("fastify");
const common_1 = require("../common");
const log_1 = require("../log");
const service_1 = require("../service");
let logger;
const api = {};
const fast = fastify({ trustProxy: true });
let targetPort = 0;
function init(cfg, callback) {
    logger = new log_1.Log(`msbase_fastify`);
    if (cfg.targetPort)
        targetPort = cfg.targetPort;
    const start = () => {
        if (!cfg.port)
            return;
        try {
            _.forEach(cfg.apipath ? cfg.apipath : ['./build/services/'], common_1.requiredir);
        }
        catch (error) {
            logger.log(error.message);
        }
        logger.log('api initialized');
        // 路由 及 熔断   
        let circuitBreakerOpt = { threshold: 3, timeout: 3000, resetTimeout: 3000 };
        if (cfg.circuitBreaker)
            circuitBreakerOpt = Object.assign(Object.assign({}, circuitBreakerOpt), cfg.circuitBreaker);
        fast.register(require('fastify-circuit-breaker'), circuitBreakerOpt);
        // 压缩
        fast.register(require('fastify-compress'), { global: false });
        try {
            const route = cfg.routefile ? require(path.resolve(cfg.routefile)) : null;
            if (route)
                route(fast);
        }
        catch (error) {
            logger.log(error.message);
        }
        _.keys(api).length > 0 && fast.register(function (instance, opts, next) {
            instance.route({
                method: 'POST',
                url: '/:cmd/',
                // beforeHandler: instance.circuitBreaker(),
                handler: (request, reply) => __awaiter(this, void 0, void 0, function* () {
                    let payload = {};
                    const start = Date.now();
                    const name = request.params.cmd.toLowerCase();
                    const bodyJson = JSON.stringify(request.body);
                    logger.debug(`1-api-${name} args-${bodyJson}`, { method_name: name });
                    try {
                        const action = api[name];
                        if (!action)
                            throw new Error(`${name} does not exist in ${cfg.name}`);
                        payload.result = yield action(request.body);
                    }
                    catch (error) {
                        payload.error = error.message;
                    }
                    const hs = Date.now() - start;
                    let spend_time = Math.floor(hs / 50);
                    if (spend_time > 99)
                        spend_time = 99;
                    logger.debug(`2-api-${name} args-${bodyJson} result-${JSON.stringify(payload)} 耗时-${hs}`, { method_name: name, spend_time: spend_time });
                    // reply.send(payload)
                    reply.compress(payload);
                })
            });
            console.log('start ms api route');
            next();
        });
        fast.listen(cfg.port, '0.0.0.0', (err, address) => {
            if (err)
                throw err;
            logger.info(`server listening on ${address}`);
        });
    };
    callback ? callback(start) : start();
}
exports.init = init;
function add(args, callback) {
    api[args.cmd] = callback;
    console.log(`api '${args.cmd}' success`);
}
exports.add = add;
function act(args, isThrowError = false) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!args.topic || !args.cmd)
            throw new Error('topic or cmd is null');
        if (args.topic)
            args.topic = args.topic.toLowerCase();
        if (args.cmd)
            args.cmd = args.cmd.toLowerCase();
        const args_obj = _.pick(args, ['data', 'context']);
        const body = JSON.stringify(args_obj);
        if (args.topic === service_1.config.name)
            return api[args.cmd](Object.assign({}, args_obj));
        const url = `http://service-${args.topic}${targetPort ? (':' + targetPort) : ''}/${args.cmd}/`;
        const start = Date.now();
        let ret = yield rp.post(url, { body, gzip: true, forever: true, headers: { 'Content-Type': 'application/json' } })
            .then(body => JSON.parse(body))
            .catch(e => { return { error: e.message }; });
        const hs = Date.now() - start;
        let spend_time = Math.floor(hs / 50);
        if (spend_time > 99)
            spend_time = 99;
        const msg = `act--${url}|${body}|${JSON.stringify(ret)}|${hs}`;
        const opts = { method_name: args.cmd, spend_time: spend_time };
        logger.debug(msg, opts);
        if (ret) {
            if ('error' in ret) {
                logger.error(msg, opts);
                if (isThrowError)
                    throw new Error(ret.error);
            }
            if ('result' in ret) {
                ret = ret.result;
            }
        }
        return ret;
    });
}
exports.act = act;
//# sourceMappingURL=fast.js.map