UNPKG

multi-lane-manager

Version:

Nacos 泳道管理与请求路由组件

337 lines (335 loc) 17.1 kB
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