"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 });
const MsConfig_1 = require("../mslib/MsConfig");
const HttpUtils_1 = require("./HttpUtils");
const CommUtils_1 = require("./CommUtils");
const MsConsts_1 = require("../defines/MsConsts");
const js_sha256_1 = require("js-sha256");
/**
 * 负载均衡工具，用于从主注册中心拉取微服务主机列表
 * @author wufenglin@rd.keytop.com.cn
 * @date 2010-08-04
 */
class MsLoadBalanceUtils {
    constructor() {
        /**
         * 负载均衡缓存
         */
        this.loadBalanceMap = new Map();
    }
    /**
     * 获取负载均衡信息
     * @param pid  项目ID
     * @param version 版本号
     * @param reload 是否需要重新加载
     */
    getLoadBalance(pid, version, reload) {
        return __awaiter(this, void 0, void 0, function* () {
            const key = `${pid}/${version}`;
            let result = this.loadBalanceMap.get(key);
            if (result && !reload) {
                return result;
            }
            result = yield this.httpGetLoadBalance(pid, version);
            if (result != null) {
                this.loadBalanceMap.set(key, result);
            }
            return result;
        });
    }
    /**
     * 更新缓存
     */
    updateCache() {
        return __awaiter(this, void 0, void 0, function* () {
            for (let [key, value] of this.loadBalanceMap.entries()) {
                const pid = CommUtils_1.CommUtils.leftStrEx(key, "/");
                const version = CommUtils_1.CommUtils.rightStr(key, "/");
                const loadBalance = yield this.httpGetLoadBalance(pid, version);
                if (loadBalance) {
                    this.loadBalanceMap.set(key, loadBalance);
                }
            }
        });
    }
    /**
     * http请求获取负载均衡列表
     * @param pid    项目ID
     * @param version 版本号
     */
    httpGetLoadBalance(pid, version) {
        return __awaiter(this, void 0, void 0, function* () {
            const headers = {
                msClientVersion: MsConsts_1.MsConsts.MS_CLIENT_VERSION,
                pid: pid,
                version: version
            };
            this.sign(headers);
            const response = yield HttpUtils_1.default.get(MsConfig_1.default.masterRegisterUrl + '/getRouteMs', {}, headers);
            if (!response.success) {
                throw new Error(response.message);
            }
            const msRunningTargets = response.attributes["msRunningTargets"];
            if (!msRunningTargets) {
                throw new Error(`未找到负载均衡主机 service: ${pid}${version}`);
            }
            if (msRunningTargets.length == 0) {
                throw new Error(`此微服务(${pid}/${version}/${MsConfig_1.default.envCode})未找到对应的主机记录，请确保已部署，并设置了默认运行版本!`);
            }
            if (!response.attributes["msRunning"]) {
                throw new Error(`未找到对应的微服务注册记录: ${pid}${version}`);
            }
            const sideCarLoadBalance = new SideCarLoadBalance(response.attributes["msRunning"]);
            sideCarLoadBalance.targetList = msRunningTargets;
            return sideCarLoadBalance;
        });
    }
    sign(headers) {
        const timestamp = Number.parseInt((new Date().getTime() / 1000).toString());
        headers["timestamp"] = timestamp;
        const signSrc = MsConfig_1.default.appId + timestamp + MsConfig_1.default.appKey;
        const sign = js_sha256_1.sha256(signSrc);
        headers["sign"] = sign;
        headers["appId"] = MsConfig_1.default.appId;
        headers[MsConfig_1.default.headerVariableName] = MsConfig_1.default.appId;
        headers["envCode"] = MsConfig_1.default.envCode;
    }
}
exports.MsLoadBalanceUtils = MsLoadBalanceUtils;
class SideCarLoadBalance {
    constructor(msRunning) {
        this.index = 0;
        this.msRunning = msRunning;
        this.pid = this.msRunning.pid;
        this.version = this.msRunning.projectVersion;
        this.contextPath = this.msRunning.contextPath;
    }
    /**
     * 获取负载均衡主机
     */
    getTarget() {
        const { targetList, index } = this;
        if (!targetList || targetList.length == 0) {
            return undefined;
        }
        const len = targetList.length;
        if (len == 1) {
            return targetList[0];
        }
        let tmp = this.index;
        if (tmp >= len) {
            tmp = 0;
        }
        for (let i = tmp; i < len; i++) {
            const result = targetList[i];
            if (result.enabled) {
                this.index = i + 1;
                return result;
            }
        }
        const random = Math.floor(Math.random() * len);
        //没有满足条件的，随机取一个
        return targetList[random];
    }
}
exports.SideCarLoadBalance = SideCarLoadBalance;
class MsRunning {
}
exports.MsRunning = MsRunning;
class MsRunningTarget {
}
exports.MsRunningTarget = MsRunningTarget;
