feat(port): 实现智能端口管理系统

- 新增端口管理器类,支持端口分配、验证和缓存管理
- 实现环境优先级策略,根据环境自动选择合适的端口范围
- 集成租户识别系统,为每个租户分配独立端口
- 添加端口分配结果统计和历史记录查询功能
- 优化端口缓存机制,自动清理过期绑定
This commit is contained in:
2025-09-03 18:52:39 +08:00
parent 8c75b5d349
commit 7052ccce61
33 changed files with 6704 additions and 38 deletions

415
src/lib/port-strategy.ts Normal file
View File

@@ -0,0 +1,415 @@
/**
* 环境端口策略配置
* 类似租户识别系统的环境优先级策略
*/
import type { PortStrategy } from './port-manager';
// 环境类型
export type Environment = 'development' | 'test' | 'staging' | 'production';
// 端口策略优先级
export interface PortPriority {
environment: Environment;
priority: number; // 数字越小优先级越高
description: string;
}
// 环境端口策略配置
export interface EnvironmentPortStrategy extends PortStrategy {
environment: Environment;
priority: number;
autoDetect: boolean;
fallbackStrategy?: EnvironmentPortStrategy;
restrictions: {
allowedHosts: string[];
blockedPorts: number[];
requireHttps: boolean;
};
}
// 端口分配模式
export enum PortAllocationMode {
TENANT_BASED = 'tenant-based', // 基于租户分配
SEQUENTIAL = 'sequential', // 顺序分配
RANDOM = 'random', // 随机分配
HASH_BASED = 'hash-based' // 基于哈希分配
}
// 环境检测器
export class EnvironmentDetector {
/**
* 检测当前环境
*/
static detectEnvironment(): Environment {
// 1. 检查环境变量
const nodeEnv = process.env.NODE_ENV;
if (nodeEnv) {
switch (nodeEnv.toLowerCase()) {
case 'development':
case 'dev':
return 'development';
case 'test':
case 'testing':
return 'test';
case 'staging':
case 'stage':
return 'staging';
case 'production':
case 'prod':
return 'production';
}
}
// 2. 检查域名
const hostname = window.location.hostname;
if (hostname.includes('localhost') || hostname.includes('127.0.0.1')) {
return 'development';
}
if (hostname.includes('test') || hostname.includes('staging')) {
return 'test';
}
if (hostname.includes('prod') || hostname.includes('www')) {
return 'production';
}
// 3. 检查端口
const port = window.location.port;
if (port && parseInt(port) < 4000) {
return 'development';
}
// 默认返回开发环境
return 'development';
}
/**
* 获取环境建议
*/
static getEnvironmentRecommendation(): {
detected: Environment;
confidence: number;
reasons: string[];
suggestions: string[];
} {
const reasons: string[] = [];
const suggestions: string[] = [];
let confidence = 0;
const nodeEnv = process.env.NODE_ENV;
const hostname = window.location.hostname;
const port = window.location.port;
const protocol = window.location.protocol;
// 分析环境变量
if (nodeEnv) {
reasons.push(`NODE_ENV: ${nodeEnv}`);
confidence += 40;
} else {
suggestions.push('建议设置 NODE_ENV 环境变量');
}
// 分析域名
if (hostname.includes('localhost')) {
reasons.push('域名包含 localhost');
confidence += 30;
} else if (hostname.includes('test')) {
reasons.push('域名包含 test');
confidence += 25;
} else if (hostname.includes('prod')) {
reasons.push('域名包含 prod');
confidence += 35;
}
// 分析协议
if (protocol === 'https:') {
reasons.push('使用 HTTPS 协议');
confidence += 10;
} else {
suggestions.push('生产环境建议使用 HTTPS');
}
// 分析端口
if (port) {
const portNum = parseInt(port);
if (portNum >= 3000 && portNum < 4000) {
reasons.push('使用开发端口范围');
confidence += 15;
}
}
return {
detected: this.detectEnvironment(),
confidence: Math.min(confidence, 100),
reasons,
suggestions
};
}
}
// 端口策略管理器
export class PortStrategyManager {
private strategies: Map<Environment, EnvironmentPortStrategy>;
private currentEnvironment: Environment;
constructor() {
this.currentEnvironment = EnvironmentDetector.detectEnvironment();
this.strategies = new Map();
this.initializeDefaultStrategies();
}
/**
* 初始化默认策略
*/
private initializeDefaultStrategies(): void {
// 开发环境策略
this.strategies.set('development', {
environment: 'development',
priority: 1,
basePort: 3000,
portRange: [3000, 3999],
tenantOffset: 10,
environmentOffset: 0,
maxRetries: 50,
autoDetect: true,
restrictions: {
allowedHosts: ['localhost', '127.0.0.1', '0.0.0.0'],
blockedPorts: [],
requireHttps: false
}
});
// 测试环境策略
this.strategies.set('test', {
environment: 'test',
priority: 2,
basePort: 4000,
portRange: [4000, 4999],
tenantOffset: 5,
environmentOffset: 1000,
maxRetries: 30,
autoDetect: true,
restrictions: {
allowedHosts: ['localhost', '127.0.0.1', 'test.local'],
blockedPorts: [4444, 4567], // 避免与其他测试工具冲突
requireHttps: false
}
});
// 预发布环境策略
this.strategies.set('staging', {
environment: 'staging',
priority: 3,
basePort: 5000,
portRange: [5000, 5999],
tenantOffset: 3,
environmentOffset: 2000,
maxRetries: 20,
autoDetect: true,
restrictions: {
allowedHosts: ['staging.local', 'stage.example.com'],
blockedPorts: [],
requireHttps: true
}
});
// 生产环境策略
this.strategies.set('production', {
environment: 'production',
priority: 4,
basePort: 8080,
portRange: [8080, 8999],
tenantOffset: 1,
environmentOffset: 5000,
maxRetries: 10,
autoDetect: false, // 生产环境不自动检测
restrictions: {
allowedHosts: ['0.0.0.0'], // 生产环境通常绑定所有接口
blockedPorts: [8080, 8443], // 避免与常用服务冲突
requireHttps: true
}
});
}
/**
* 获取当前环境策略
*/
getCurrentStrategy(): EnvironmentPortStrategy {
const strategy = this.strategies.get(this.currentEnvironment);
if (!strategy) {
console.warn(`未找到环境 ${this.currentEnvironment} 的策略,使用开发环境策略`);
return this.strategies.get('development')!;
}
return strategy;
}
/**
* 获取指定环境策略
*/
getStrategy(environment: Environment): EnvironmentPortStrategy | undefined {
return this.strategies.get(environment);
}
/**
* 设置环境策略
*/
setStrategy(environment: Environment, strategy: EnvironmentPortStrategy): void {
this.strategies.set(environment, strategy);
console.log(`✅ 已更新 ${environment} 环境的端口策略`);
}
/**
* 获取推荐策略(基于环境优先级)
*/
getRecommendedStrategy(): {
primary: EnvironmentPortStrategy;
fallback: EnvironmentPortStrategy[];
reasoning: string[];
} {
const current = this.getCurrentStrategy();
const reasoning: string[] = [];
const fallback: EnvironmentPortStrategy[] = [];
reasoning.push(`当前环境: ${this.currentEnvironment}`);
reasoning.push(`优先级: ${current.priority}`);
// 获取备选策略(按优先级排序)
const allStrategies = Array.from(this.strategies.values())
.filter(s => s.environment !== this.currentEnvironment)
.sort((a, b) => a.priority - b.priority);
fallback.push(...allStrategies);
// 环境特定的推理
switch (this.currentEnvironment) {
case 'development':
reasoning.push('开发环境优先考虑端口可用性和调试便利性');
break;
case 'test':
reasoning.push('测试环境需要隔离性和可重复性');
break;
case 'staging':
reasoning.push('预发布环境模拟生产环境配置');
break;
case 'production':
reasoning.push('生产环境优先考虑安全性和稳定性');
break;
}
return { primary: current, fallback, reasoning };
}
/**
* 验证端口策略
*/
validateStrategy(strategy: EnvironmentPortStrategy): {
isValid: boolean;
errors: string[];
warnings: string[];
} {
const errors: string[] = [];
const warnings: string[] = [];
// 检查端口范围
if (strategy.portRange[0] >= strategy.portRange[1]) {
errors.push('端口范围无效:起始端口必须小于结束端口');
}
if (strategy.portRange[0] < 1024 && strategy.environment === 'production') {
warnings.push('生产环境使用系统端口(<1024可能需要管理员权限');
}
// 检查基础端口
if (strategy.basePort < strategy.portRange[0] || strategy.basePort > strategy.portRange[1]) {
errors.push('基础端口不在允许的端口范围内');
}
// 检查租户偏移
if (strategy.tenantOffset <= 0) {
warnings.push('租户偏移为0可能导致端口冲突');
}
// 检查环境特定规则
if (strategy.environment === 'production' && !strategy.restrictions.requireHttps) {
warnings.push('生产环境建议启用 HTTPS');
}
if (strategy.environment === 'development' && strategy.restrictions.requireHttps) {
warnings.push('开发环境启用 HTTPS 可能增加配置复杂度');
}
return {
isValid: errors.length === 0,
errors,
warnings
};
}
/**
* 获取环境统计信息
*/
getEnvironmentStats(): {
current: Environment;
available: Environment[];
strategies: Array<{
environment: Environment;
priority: number;
portRange: [number, number];
isValid: boolean;
}>;
} {
const strategies = Array.from(this.strategies.entries()).map(([env, strategy]) => ({
environment: env,
priority: strategy.priority,
portRange: strategy.portRange,
isValid: this.validateStrategy(strategy).isValid
}));
return {
current: this.currentEnvironment,
available: Array.from(this.strategies.keys()),
strategies: strategies.sort((a, b) => a.priority - b.priority)
};
}
/**
* 切换环境
*/
switchEnvironment(environment: Environment): boolean {
if (!this.strategies.has(environment)) {
console.error(`环境 ${environment} 不存在`);
return false;
}
this.currentEnvironment = environment;
console.log(`🔄 已切换到 ${environment} 环境`);
return true;
}
}
// 导出默认实例
export const portStrategyManager = new PortStrategyManager();
// 导出环境优先级配置
export const ENVIRONMENT_PRIORITIES: PortPriority[] = [
{
environment: 'development',
priority: 1,
description: '开发环境 - 最高优先级,注重便利性'
},
{
environment: 'test',
priority: 2,
description: '测试环境 - 高优先级,注重隔离性'
},
{
environment: 'staging',
priority: 3,
description: '预发布环境 - 中等优先级,模拟生产'
},
{
environment: 'production',
priority: 4,
description: '生产环境 - 最低优先级,注重安全性'
}
];