tencentcloud-edgeone-migration-nodejs-v2
Version:
tencentcloud cdn config copy to edgeone
217 lines • 7.77 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.kProtoPath = exports.ProtobufFormat = exports.address2Instance = exports.kInstanceLocalVersion = exports.transformStatusChange = exports.protobuf2ms = exports.ms2protobuf = exports.isAnyAddr = exports.fastestRemote = exports.address2Endpoint = exports.isValidPort = exports.inspectEndpoints = void 0;
const net = require("net");
const path = require("path");
const __1 = require("../../..");
const utils_1 = require("../../../utils");
const types_1 = require("./types");
// #region Network
const kAnyAddrRegex = /^(0|[^0-9a-z])+$/i;
const kDetectionTimeout = 1 * utils_1.kSeconds;
/**
* 转换为可读地址
* @param inputs `EndPoint` 类型地址
*/
const inspectEndpoints = (inputs) => inputs.map(({ host, port }) => `${host}:${port}`).join(", ");
exports.inspectEndpoints = inspectEndpoints;
/**
* 判断端口号是否合法
* @param input 端口号
*/
const isValidPort = (input) => Number.isInteger(input) && input >= 0 && input <= (2 ** 16) - 1;
exports.isValidPort = isValidPort;
/**
* 地址类型转换
* `string` ---> `EndPoint`
* @param input `string` 类型地址
* @returns `EndPoint` 类型地址
*/
function address2Endpoint(input) {
const [host, port] = input.split(":");
const normalizedPort = Number.parseInt(port, 10);
if (!(0, exports.isValidPort)(normalizedPort)) {
throw new __1.ArgumentError("invalid port");
}
return {
host,
port: normalizedPort
};
}
exports.address2Endpoint = address2Endpoint;
/**
* 探测连接速度最快的远端节点
* @param hosts 待探测远端节点列表
* @param ms 最长探测时长
* @returns 最快响应远端及其对应的本地节点 IP
*/
async function fastestRemote(hosts, ms = kDetectionTimeout) {
const normalized = [];
hosts.forEach((host) => {
switch (typeof host) {
case "string": {
normalized.push(address2Endpoint(host));
break;
}
case "object": {
normalized.push(host);
break;
}
default: {
throw new __1.ArgumentError("invalid hosts");
}
}
});
return new Promise((resolve, reject) => {
let isResolved = false;
let rejectCount = 0;
normalized.forEach((host) => {
const socket = net.connect(Object.assign(Object.assign({}, host), { timeout: ms }))
.once("connect", () => {
if (!isResolved) {
const { localAddress, localPort } = socket;
if (localAddress && localPort && localPort > 0) {
isResolved = true;
resolve({
local: {
host: localAddress,
port: localPort
},
remote: host
});
}
else {
rejectCount += 1;
if (rejectCount === hosts.length) {
reject(new __1.NetworkError(`all remote hosts(${(0, exports.inspectEndpoints)(normalized)}) dead`));
}
}
}
socket.destroy();
})
.once("error", () => {
if (!isResolved) {
rejectCount += 1;
if (rejectCount === hosts.length) {
reject(new __1.NetworkError(`all remote hosts(${(0, exports.inspectEndpoints)(normalized)}) dead`));
}
}
})
.unref();
});
});
}
exports.fastestRemote = fastestRemote;
/**
* 判断特定 IP(4/6) 是否为任意地址 `INADDR_ANY`
* @param ip IP 地址
* @returns 判定结果
*/
const isAnyAddr = (ip) => kAnyAddrRegex.test(ip);
exports.isAnyAddr = isAnyAddr;
function ms2protobuf(ms, format = ProtobufFormat.Original) {
switch (format) {
case ProtobufFormat.Original: {
return {
seconds: ms / utils_1.kSeconds,
nanos: (ms % utils_1.kSeconds) * utils_1.kSeconds * utils_1.kNanos
};
}
case ProtobufFormat.JSON: {
return `${ms / utils_1.kSeconds}s`;
}
default: {
(0, utils_1.UNREACHABLE)();
}
}
(0, utils_1.UNREACHABLE)(); /** Stub */
}
exports.ms2protobuf = ms2protobuf;
/**
* `protobuf` 时间格式转毫秒
* @param time `protobuf` 时间格式
*/
function protobuf2ms(time) {
switch (typeof time) {
case "string": { /** ProtobufFormat.JSON */
if (!time.endsWith("s")) {
return NaN;
}
return parseFloat(time) * utils_1.kSeconds;
}
case "object": {
const { seconds, nanos } = time;
if (typeof seconds !== "number" || typeof nanos !== "number") {
return NaN;
}
return Math.floor((seconds * utils_1.kSeconds) + (nanos / utils_1.kNanos));
}
default: {
return NaN;
}
}
(0, utils_1.UNREACHABLE)(); /** Stub */
}
exports.protobuf2ms = protobuf2ms;
// #endregion
/**
* 转换实例状态至熔断器变更类型
* @description `StatusChange` 为熔断器变更类型而非实例的状态,_也就是说,这里所需输出的状态与实例状态相反_
* @param before 前一状态
* @param after 下一状态
*/
const transformStatusChange = (before, after) => {
if (before === 0 /* Normal */ && after === 3 /* Fused */) {
return types_1.StatusChange.CloseToOpen;
}
if (before === 2 /* HalfClose */ || before === 1 /* HalfOpen */) {
if (after === 0 /* Normal */) {
return types_1.StatusChange.HalfOpenToClose;
}
if (after === 3 /* Fused */) {
return types_1.StatusChange.HalfOpenToOpen;
}
}
else if (before === 3 /* Fused */
&& (after === 2 /* HalfClose */ || after === 1 /* HalfOpen */)) {
return types_1.StatusChange.OpenToHalfOpen;
}
return types_1.StatusChange.Unknown;
};
exports.transformStatusChange = transformStatusChange;
/**
* 本地实例版本号
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
exports.kInstanceLocalVersion = "local";
/**
* 通过地址列表生成对应实例列表
* @param input 地址列表
* @param protocol 协议
*/
const address2Instance = (input, protocol) => input.map((address) => {
const endpoint = address2Endpoint(address);
return Object.assign({ dynamicWeight: 0, logicSet: "", priority: 9, status: 0 /* Normal */, staticWeight: 100, protocol, version: exports.kInstanceLocalVersion, metadata: {
protocol
}, location: Object.assign({}, __1.blankLocation /** copy */), vpcId: "", id: `${endpoint.host}:${endpoint.port}` }, endpoint);
});
exports.address2Instance = address2Instance;
/**
* `protobuf` 编码格式
*/
var ProtobufFormat;
(function (ProtobufFormat) {
/** 原始格式 */
ProtobufFormat[ProtobufFormat["Original"] = 0] = "Original";
/** JSON 格式 */
ProtobufFormat[ProtobufFormat["JSON"] = 1] = "JSON";
})(ProtobufFormat = exports.ProtobufFormat || (exports.ProtobufFormat = {}));
/**
* Proto definition directory
*/
exports.kProtoPath = Object.freeze({
[types_1.ServiceType.Discover]: path.join(__dirname, "discover-pb"),
[types_1.ServiceType.Monitor]: path.join(__dirname, "monitor-pb"),
[types_1.ServiceType.Ratelimit]: path.join(__dirname, "ratelimit-pb")
});
//# sourceMappingURL=utils.js.map