multi-lane-manager
Version:
Nacos 泳道管理与请求路由组件
337 lines (335 loc) • 17.1 kB
JavaScript
import {
logger
} from "./chunk-W2IK3WU4.mjs";
import {
DEFAULT_HOST,
DEFAULT_LANE_COOKIE_ENABLED,
DEFAULT_LANE_ENABLED,
DEFAULT_LANE_GROUP_NAME,
DEFAULT_LANE_HEARTBEAT_INTERVAL,
DEFAULT_LANE_ID,
DEFAULT_LANE_INSTANCE_TTL,
DEFAULT_LANE_NAMESPACE,
DEFAULT_LANE_PROXY_TIMEOUT,
DEFAULT_LANE_REGISTRATION_TIMEOUT,
DEFAULT_LANE_SERVER,
DEFAULT_LANE_TARGET_HEADER,
DEFAULT_SERVICE_NAME,
getBooleanEnv,
getEnvOrDefault,
getNumberEnv
} from "./chunk-U24KVOYL.mjs";
// src/utils/config.ts
import * as os from "os";
import * as path from "path";
import * as fs from "fs";
function isPrivateIP(ip) {
const parts = ip.split(".").map(Number);
if (parts.length !== 4) return false;
const [a, b] = parts;
return a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
}
function shouldSkipIP(ip, interfaceName) {
if (ip.startsWith("172.17.")) {
logger.debug(`\u23ED\uFE0F \u8DF3\u8FC7Docker\u6865\u63A5\u7F51\u7EDC\u5730\u5740: ${ip} (\u63A5\u53E3: ${interfaceName})`);
return true;
}
const parts = ip.split(".").map(Number);
if (parts[0] === 172 && parts[1] >= 17 && parts[1] <= 31) {
logger.debug(`\u23ED\uFE0F \u8DF3\u8FC7Docker\u7F51\u7EDC\u5730\u5740: ${ip} (\u63A5\u53E3: ${interfaceName})`);
return true;
}
const skipInterfaces = ["docker0", "br-", "veth"];
if (skipInterfaces.some((skip) => interfaceName.startsWith(skip))) {
logger.debug(`\u23ED\uFE0F \u8DF3\u8FC7\u865A\u62DF\u63A5\u53E3: ${interfaceName} (IP: ${ip})`);
return true;
}
return false;
}
function detectInstanceIP() {
logger.info(`\u{1F50D} \u5F00\u59CB\u81EA\u52A8\u68C0\u6D4B\u5B9E\u4F8BIP\u5730\u5740...`);
try {
const networkInterfaces2 = os.networkInterfaces();
logger.debug(`\u{1F50D} \u68C0\u6D4B\u5230\u7684\u7F51\u7EDC\u63A5\u53E3: ${JSON.stringify(Object.keys(networkInterfaces2))}`);
const containerInterfaces = [
"eth0",
// 最常见的容器网络接口
"eth1",
// 多网卡容器
"ens3",
// 云环境常见接口
"ens4"
// 云环境常见接口
];
const physicalInterfaces = [
"ens160",
// VMware虚拟机
"ens192",
// VMware虚拟机
"enp0s3",
// VirtualBox
"enp0s8",
// VirtualBox
"en0",
// macOS
"en1",
// macOS
"wlan0"
// 无线网络
];
for (const interfaceName of containerInterfaces) {
const networkInterface = networkInterfaces2[interfaceName];
if (networkInterface) {
for (const addr of networkInterface) {
if (addr.family === "IPv4" && !addr.internal && !shouldSkipIP(addr.address, interfaceName)) {
logger.info(`\u2705 \u4ECE\u5BB9\u5668\u7F51\u7EDC\u63A5\u53E3 ${interfaceName} \u83B7\u53D6IP\u5730\u5740: ${addr.address}`);
return addr.address;
}
}
}
}
for (const interfaceName of physicalInterfaces) {
const networkInterface = networkInterfaces2[interfaceName];
if (networkInterface) {
for (const addr of networkInterface) {
if (addr.family === "IPv4" && !addr.internal && !shouldSkipIP(addr.address, interfaceName)) {
logger.info(`\u2705 \u4ECE\u7269\u7406\u7F51\u7EDC\u63A5\u53E3 ${interfaceName} \u83B7\u53D6IP\u5730\u5740: ${addr.address}`);
return addr.address;
}
}
}
}
const candidateIPs = [];
for (const [interfaceName, addresses] of Object.entries(networkInterfaces2)) {
if (!addresses) continue;
for (const addr of addresses) {
if (addr.family === "IPv4" && !addr.internal && !shouldSkipIP(addr.address, interfaceName)) {
candidateIPs.push({
ip: addr.address,
interface: interfaceName,
isPrivate: isPrivateIP(addr.address)
});
}
}
}
if (candidateIPs.length > 0) {
const privateIPs = candidateIPs.filter((candidate) => candidate.isPrivate);
if (privateIPs.length > 0) {
const selected2 = privateIPs[0];
logger.info(`\u2705 \u9009\u62E9\u79C1\u6709\u7F51\u7EDCIP: ${selected2.ip} (\u63A5\u53E3: ${selected2.interface})`);
return selected2.ip;
}
const selected = candidateIPs[0];
logger.info(`\u2705 \u9009\u62E9\u516C\u7F51IP: ${selected.ip} (\u63A5\u53E3: ${selected.interface})`);
return selected.ip;
}
} catch (error) {
logger.warn(`\u26A0\uFE0F \u81EA\u52A8\u68C0\u6D4B\u7F51\u7EDC\u63A5\u53E3\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
}
if (process.env.POD_IP && process.env.POD_IP !== "localhost" && process.env.POD_IP !== "127.0.0.1") {
logger.info(`\u{1F3AF} \u7F51\u7EDC\u63A5\u53E3\u68C0\u6D4B\u5931\u8D25\uFF0C\u4F7F\u7528Kubernetes Pod IP: ${process.env.POD_IP}`);
return process.env.POD_IP;
}
if (process.env.CONTAINER_IP && process.env.CONTAINER_IP !== "localhost" && process.env.CONTAINER_IP !== "127.0.0.1") {
logger.info(`\u{1F4E6} \u7F51\u7EDC\u63A5\u53E3\u68C0\u6D4B\u5931\u8D25\uFF0C\u4F7F\u7528\u5BB9\u5668\u73AF\u5883\u53D8\u91CFIP: ${process.env.CONTAINER_IP}`);
return process.env.CONTAINER_IP;
}
logger.error(`\u274C \u65E0\u6CD5\u81EA\u52A8\u68C0\u6D4B\u5230\u6709\u6548\u7684IP\u5730\u5740\uFF01`);
logger.error(`\u{1F4A1} \u8FD9\u901A\u5E38\u53D1\u751F\u5728\u4EE5\u4E0B\u60C5\u51B5\uFF1A`);
logger.error(` 1. \u5BB9\u5668\u7F51\u7EDC\u914D\u7F6E\u5F02\u5E38`);
logger.error(` 2. \u7F51\u7EDC\u63A5\u53E3\u540D\u79F0\u4E0D\u5728\u9884\u671F\u8303\u56F4\u5185`);
logger.error(` 3. \u6240\u6709\u68C0\u6D4B\u5230\u7684IP\u90FD\u88AB\u8FC7\u6EE4\u6389\u4E86`);
logger.error(`\u{1F527} \u89E3\u51B3\u65B9\u6848\uFF1A`);
logger.error(` - \u5728Kubernetes\u4E2D\u4F7F\u7528Downward API\u6CE8\u5165POD_IP`);
logger.error(` - \u68C0\u67E5\u5BB9\u5668\u7F51\u7EDC\u914D\u7F6E`);
logger.error(` - \u5982\u679C\u5FC5\u8981\uFF0C\u53EF\u4EE5\u8BBE\u7F6EHOST\u73AF\u5883\u53D8\u91CF\u4F5C\u4E3A\u4E34\u65F6\u89E3\u51B3\u65B9\u6848`);
return DEFAULT_HOST;
}
var configCache = null;
function getConfig() {
if (configCache) {
return configCache;
}
configCache = createConfig();
return configCache;
}
function clearConfigCache() {
configCache = null;
logger.debug("\u{1F504} \u914D\u7F6E\u7F13\u5B58\u5DF2\u6E05\u9664");
}
function createConfig() {
const nacosServer = process.env.LANE_SERVER || process.env.NACOS_SERVER || DEFAULT_LANE_SERVER;
logger.debug(`\u{1F50D} Nacos\u670D\u52A1\u5668\u914D\u7F6E: LANE_SERVER=${process.env.LANE_SERVER}, NACOS_SERVER=${process.env.NACOS_SERVER}, DEFAULT_LANE_SERVER=${DEFAULT_LANE_SERVER}`);
logger.debug(`\u{1F50D} \u6700\u7EC8\u4F7F\u7528\u7684Nacos\u670D\u52A1\u5668: ${nacosServer}`);
const parts = nacosServer.split(":");
const nacosServerAddr = parts[0] || "localhost";
const nacosServerPort = parts.length > 1 ? parts[1] : "8848";
logger.debug(`\u{1F50D} \u89E3\u6790\u540E\u7684Nacos\u5730\u5740: ${nacosServerAddr}, \u7AEF\u53E3: ${nacosServerPort}`);
logger.debug(`\u{1F50D} \u670D\u52A1\u540D\u79F0\u83B7\u53D6\u8FC7\u7A0B\u5F00\u59CB...`);
logger.debug(`\u{1F50D} \u73AF\u5883\u53D8\u91CF SERVICE_NAME=${process.env.SERVICE_NAME}`);
logger.debug(`\u{1F50D} DEFAULT_SERVICE_NAME=${DEFAULT_SERVICE_NAME}`);
let packageJsonName = "\u672A\u68C0\u6D4B";
try {
const possiblePaths = [
// 优先检查 server/package.json (适用于 node server/index.mjs 启动方式)
path.resolve(process.cwd(), "server", "package.json"),
// 当前工作目录
path.resolve(process.cwd(), "package.json"),
// 当前工作目录的父目录(可能是项目根目录)
path.resolve(process.cwd(), "..", "package.json"),
// 常见的服务器输出目录
path.resolve(process.cwd(), "server", "..", "package.json"),
path.resolve(process.cwd(), ".output", "server", "..", "package.json"),
path.resolve(process.cwd(), "dist", "..", "package.json"),
path.resolve(process.cwd(), "build", "..", "package.json"),
// Nuxt输出目录
path.resolve(process.cwd(), ".output", "package.json"),
// 应用根目录(如果设置了APP_ROOT环境变量)
...process.env.APP_ROOT ? [path.resolve(process.env.APP_ROOT, "package.json")] : [],
// 向上查找两级目录
path.resolve(process.cwd(), "..", "..", "package.json")
];
for (const packageJsonPath of possiblePaths) {
if (fs.existsSync(packageJsonPath)) {
logger.debug(`\u{1F50D} \u5C1D\u8BD5\u8BFB\u53D6 package.json: ${packageJsonPath}`);
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
if (packageJson && packageJson.name) {
packageJsonName = packageJson.name;
logger.debug(`\u2705 \u6210\u529F\u4ECE ${packageJsonPath} \u8BFB\u53D6\u5230 package.json\uFF0Cname: ${packageJsonName}`);
if (packageJsonPath.includes("server/package.json")) {
logger.info(`\u{1F680} \u4ECE server/package.json \u83B7\u53D6\u670D\u52A1\u540D\u79F0\uFF0C\u9002\u7528\u4E8E node server/index.mjs \u542F\u52A8\u65B9\u5F0F`);
}
break;
} else {
logger.debug(`\u26A0\uFE0F \u4ECE ${packageJsonPath} \u8BFB\u53D6\u5230 package.json\uFF0C\u4F46\u6CA1\u6709 name \u5B57\u6BB5`);
}
}
}
} catch (error) {
packageJsonName = `\u68C0\u6D4B\u51FA\u9519: ${error instanceof Error ? error.message : String(error)}`;
logger.debug(`\u274C \u8BFB\u53D6 package.json \u5931\u8D25: ${packageJsonName}`);
}
logger.debug(`\u{1F50D} package.json name=${packageJsonName}`);
let serviceName = "";
if (packageJsonName && packageJsonName !== "\u672A\u68C0\u6D4B" && packageJsonName !== "\u672A\u8BBE\u7F6E" && !packageJsonName.startsWith("\u68C0\u6D4B\u51FA\u9519")) {
serviceName = packageJsonName;
logger.info(`\u2705 \u4ECE package.json \u83B7\u53D6\u670D\u52A1\u540D\u79F0: ${serviceName}`);
} else if (process.env.SERVICE_NAME) {
serviceName = process.env.SERVICE_NAME;
logger.info(`\u2705 \u4ECE\u73AF\u5883\u53D8\u91CF SERVICE_NAME \u83B7\u53D6\u670D\u52A1\u540D\u79F0: ${serviceName}`);
} else if (process.env.NITRO_APP_NAME) {
serviceName = process.env.NITRO_APP_NAME;
logger.info(`\u2705 \u4ECE\u73AF\u5883\u53D8\u91CF NITRO_APP_NAME \u83B7\u53D6\u670D\u52A1\u540D\u79F0: ${serviceName}`);
} else if (process.env.APP_NAME) {
serviceName = process.env.APP_NAME;
logger.info(`\u2705 \u4ECE\u73AF\u5883\u53D8\u91CF APP_NAME \u83B7\u53D6\u670D\u52A1\u540D\u79F0: ${serviceName}`);
} else if (process.env.npm_package_name) {
serviceName = process.env.npm_package_name;
logger.info(`\u2705 \u4ECE\u73AF\u5883\u53D8\u91CF npm_package_name \u83B7\u53D6\u670D\u52A1\u540D\u79F0: ${serviceName}`);
} else {
serviceName = "";
logger.error(`\u274C \u8B66\u544A: \u65E0\u6CD5\u83B7\u53D6\u670D\u52A1\u540D\u79F0\uFF0C\u6CF3\u9053\u529F\u80FD\u5C06\u88AB\u7981\u7528`);
logger.error(`\u274C \u8BF7\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u4E4B\u4E00\u8BBE\u7F6E\u670D\u52A1\u540D\u79F0:`);
logger.error(` 1. \u786E\u4FDD server/package.json \u6216\u9879\u76EE\u6839\u76EE\u5F55\u7684 package.json \u4E2D\u6709 name \u5B57\u6BB5`);
logger.error(` 2. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF SERVICE_NAME`);
logger.error(` 3. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF NITRO_APP_NAME, APP_NAME \u6216 npm_package_name`);
}
logger.debug(`\u{1F50D} \u6700\u7EC8\u4F7F\u7528\u7684\u670D\u52A1\u540D\u79F0: ${serviceName || "\u672A\u8BBE\u7F6E (\u6CF3\u9053\u529F\u80FD\u5C06\u88AB\u7981\u7528)"}`);
const currentLaneId = getEnvOrDefault("LANE_ID", DEFAULT_LANE_ID);
logger.debug(`\u{1F50D} \u5F00\u59CB\u68C0\u6D4B\u5B9E\u4F8BIP\u5730\u5740...`);
const host = detectInstanceIP();
logger.info(`\u{1F310} \u6700\u7EC8\u4F7F\u7528\u7684IP\u5730\u5740: ${host}`);
const metadata = {
laneId: currentLaneId,
// 泳道 ID
environment: getEnvOrDefault("NODE_ENV", "development"),
// 环境
registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
// 注册时间
framework: "nuxt3",
// 框架
version: getEnvOrDefault("npm_package_version", "unknown"),
// 版本
hostname: os.hostname(),
// 主机名
nodeVersion: process.versions.node
// Node.js 版本
};
const hasValidServiceName = !!serviceName;
const isLaneEnabled = hasValidServiceName ? getBooleanEnv("LANE_ENABLE", DEFAULT_LANE_ENABLED) : false;
if (isLaneEnabled && !hasValidServiceName) {
logger.error(`\u274C \u9519\u8BEF: \u6CF3\u9053\u529F\u80FD\u5DF2\u542F\u7528\uFF0C\u4F46\u65E0\u6CD5\u83B7\u53D6\u6709\u6548\u7684\u670D\u52A1\u540D\u79F0\uFF0C\u5E94\u7528\u5C06\u505C\u6B62\u542F\u52A8`);
logger.error(`\u274C \u8BF7\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u4E4B\u4E00\u8BBE\u7F6E\u670D\u52A1\u540D\u79F0:`);
logger.error(` 1. \u786E\u4FDD server/package.json \u6216\u9879\u76EE\u6839\u76EE\u5F55\u7684 package.json \u4E2D\u6709 name \u5B57\u6BB5`);
logger.error(` 2. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF SERVICE_NAME`);
logger.error(` 3. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF NITRO_APP_NAME, APP_NAME \u6216 npm_package_name`);
process.exit(1);
}
if (!hasValidServiceName && !isLaneEnabled) {
logger.error(`\u274C \u8B66\u544A: \u65E0\u6CD5\u83B7\u53D6\u6709\u6548\u7684\u670D\u52A1\u540D\u79F0\uFF0C\u5DF2\u81EA\u52A8\u7981\u7528\u6CF3\u9053\u529F\u80FD`);
logger.error(`\u274C \u8BF7\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u4E4B\u4E00\u8BBE\u7F6E\u670D\u52A1\u540D\u79F0:`);
logger.error(` 1. \u786E\u4FDD server/package.json \u6216\u9879\u76EE\u6839\u76EE\u5F55\u7684 package.json \u4E2D\u6709 name \u5B57\u6BB5`);
logger.error(` 2. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF SERVICE_NAME`);
logger.error(` 3. \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF NITRO_APP_NAME, APP_NAME \u6216 npm_package_name`);
}
const config = {
// Nacos 服务器配置
nacosServerAddr,
nacosServerPort,
nacosUrl: `http://${nacosServerAddr}:${nacosServerPort}`,
nacosNamespace: getEnvOrDefault("LANE_NAMESPACE", process.env.NACOS_NAMESPACE || DEFAULT_LANE_NAMESPACE),
nacosGroupName: getEnvOrDefault("LANE_GROUP_NAME", process.env.NACOS_GROUP_NAME || DEFAULT_LANE_GROUP_NAME),
// 服务配置
serviceName,
currentLaneId,
host,
port: null,
// 初始为 null,将在服务启动时设置
// 泳道配置
targetLaneHeaderKey: (() => {
logger.debug(`\u{1F50D} \u76EE\u6807\u6CF3\u9053\u8BF7\u6C42\u5934\u952E\u540D\u83B7\u53D6\u8FC7\u7A0B\u5F00\u59CB...`);
logger.debug(`\u{1F50D} \u73AF\u5883\u53D8\u91CF LANE_TARGET_HEADER=${process.env.LANE_TARGET_HEADER}`);
logger.debug(`\u{1F50D} \u73AF\u5883\u53D8\u91CF TARGET_LANE_HEADER=${process.env.TARGET_LANE_HEADER}`);
logger.debug(`\u{1F50D} \u9ED8\u8BA4\u503C DEFAULT_LANE_TARGET_HEADER=${DEFAULT_LANE_TARGET_HEADER}`);
const headerKey = getEnvOrDefault("LANE_TARGET_HEADER", process.env.TARGET_LANE_HEADER || DEFAULT_LANE_TARGET_HEADER);
logger.debug(`\u{1F50D} \u6700\u7EC8\u4F7F\u7528\u7684\u76EE\u6807\u6CF3\u9053\u8BF7\u6C42\u5934\u952E\u540D: ${headerKey}`);
return headerKey;
})(),
// 使用前面计算的 isLaneEnabled 值
isLaneEnabled: (() => {
logger.debug(`\u{1F50D} \u6CF3\u9053\u529F\u80FD\u542F\u7528\u72B6\u6001: ${isLaneEnabled} (hasValidServiceName=${hasValidServiceName}, LANE_ENABLE=${process.env.LANE_ENABLE}, DEFAULT_LANE_ENABLED=${DEFAULT_LANE_ENABLED})`);
return isLaneEnabled;
})(),
isLaneCookieEnabled: (() => {
const enabled = getBooleanEnv("LANE_COOKIE_ENABLE", DEFAULT_LANE_COOKIE_ENABLED);
logger.debug(`\u{1F50D} Cookie\u6CF3\u9053\u68C0\u6D4B\u542F\u7528\u72B6\u6001: ${enabled} (LANE_COOKIE_ENABLE=${process.env.LANE_COOKIE_ENABLE}, DEFAULT_LANE_COOKIE_ENABLED=${DEFAULT_LANE_COOKIE_ENABLED})`);
return enabled;
})(),
// 超时配置
proxyTimeout: getNumberEnv("LANE_PROXY_TIMEOUT", process.env.PROXY_TIMEOUT ? parseInt(process.env.PROXY_TIMEOUT) : DEFAULT_LANE_PROXY_TIMEOUT),
registrationTimeout: getNumberEnv("LANE_REGISTRATION_TIMEOUT", process.env.REGISTRATION_TIMEOUT ? parseInt(process.env.REGISTRATION_TIMEOUT) : DEFAULT_LANE_REGISTRATION_TIMEOUT),
heartbeatInterval: getNumberEnv("LANE_HEARTBEAT_INTERVAL", process.env.NACOS_HEARTBEAT_INTERVAL ? parseInt(process.env.NACOS_HEARTBEAT_INTERVAL) : DEFAULT_LANE_HEARTBEAT_INTERVAL),
instanceTtl: getNumberEnv("LANE_INSTANCE_TTL", process.env.NACOS_INSTANCE_TTL ? parseInt(process.env.NACOS_INSTANCE_TTL) : DEFAULT_LANE_INSTANCE_TTL),
// 元数据
metadata
};
logger.debug("\u{1F527} \u5DF2\u521B\u5EFA\u914D\u7F6E\u5BF9\u8C61:", config);
return config;
}
function updateConfigPort(port) {
if (!configCache) {
configCache = createConfig();
}
configCache.port = port;
logger.debug(`\u{1F50C} \u914D\u7F6E\u7AEF\u53E3\u5DF2\u66F4\u65B0: ${port}`);
}
function getGlobalState() {
return global;
}
export {
getConfig,
clearConfigCache,
updateConfigPort,
getGlobalState
};
//# sourceMappingURL=chunk-EU6U6V5A.mjs.map