import 'dart:convert'; import 'package:get/get.dart'; import '../response/kr_node_list.dart'; import 'package:flutter/foundation.dart'; /// 表示出站项的模型类 class KROutboundItem { int selected = 0; // 是否选中(0=未选中,1=选中) String id = ""; // 标签 String tag = ""; // 标签 String serverAddr = ""; // 服务器地址 /// 初始化配置 Map config = {}; // 配置项 String city = ""; // 城市 String country = ""; // 国家 double latitude = 0.0; // 节点纬度 double latitudeCountry = 0.0; // 国家中心纬度 double longitude = 0.0; // 节点经度 double longitudeCountry = 0.0; // 国家中心经度 String protocol = ""; /// 延迟 RxInt urlTestDelay = 0.obs; /// URL String url = ""; @override String toString() { return 'KROutboundItem(tag: $tag, country: $country, delay: ${urlTestDelay.value}ms)'; } /// 服务器类型 /// 构造函数,接受 KrNodeListItem 对象并初始化 KROutboundItem KROutboundItem(KrNodeListItem nodeListItem) { id = nodeListItem.id.toString(); protocol = nodeListItem.protocol; latitude = nodeListItem.latitude; latitudeCountry = nodeListItem.latitudeCountry; longitude = nodeListItem.longitude; longitudeCountry = nodeListItem.longitudeCountry; tag = nodeListItem.name; // 设置标签 serverAddr = nodeListItem.serverAddr; // 设置服务器地址 city = nodeListItem.city; // 设置城市 country = nodeListItem.country; // 设置国家 // 🔧 优先使用直接字段构建配置(新API格式) // 判断条件:如果有 port 和 serverAddr,说明是新格式 if (nodeListItem.port > 0 && nodeListItem.serverAddr.isNotEmpty) { if (kDebugMode) { print('ℹ️ 节点 ${nodeListItem.name} 使用直接字段构建配置'); } _buildConfigFromFields(nodeListItem); return; } // 兜底:尝试解析 config 字段(旧API格式) if (nodeListItem.config.isEmpty) { if (kDebugMode) { print('❌ 节点 ${nodeListItem.name} 缺少配置信息(无port或config)'); } config = {}; return; } late Map json; try { json = jsonDecode(nodeListItem.config) as Map; } catch (e) { if (kDebugMode) { print('❌ 节点 ${nodeListItem.name} 的 config 解析失败: $e,尝试使用直接字段'); } if (kDebugMode) { print('📄 Config 内容: ${nodeListItem.config}'); } _buildConfigFromFields(nodeListItem); return; } switch (nodeListItem.protocol) { case "vless": final securityConfig = json["security_config"] as Map? ?? {}; // 智能设置 server_name String serverName = securityConfig["sni"] ?? ""; if (serverName.isEmpty) { serverName = nodeListItem.serverAddr; } config = { "type": "vless", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": json["port"], "uuid": nodeListItem.uuid, if (json["flow"] != null && json["flow"] != "none") "flow": json["flow"], if (json["transport"] != null && json["transport"] != "tcp") "transport": _buildTransport(json), "tls": { "enabled": json["security"] == "tls", "server_name": serverName, "insecure": securityConfig["allow_insecure"] ?? true, "utls": { "enabled": true, "fingerprint": securityConfig["fingerprint"] ?? "chrome" } } }; break; case "vmess": final securityConfig = json["security_config"] as Map? ?? {}; // 智能设置 server_name String serverName = securityConfig["sni"] ?? ""; if (serverName.isEmpty) { serverName = nodeListItem.serverAddr; } config = { "type": "vmess", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": json["port"], "uuid": nodeListItem.uuid, "alter_id": 0, "security": "auto", if (json["transport"] != null && json["transport"] != "tcp") "transport": _buildTransport(json), "tls": { "enabled": json["security"] == "tls", "server_name": serverName, "insecure": securityConfig["allow_insecure"] ?? true, "utls": {"enabled": true, "fingerprint": "chrome"} } }; break; case "shadowsocks": config = { "type": "shadowsocks", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": json["port"], "method": json["method"], "password": nodeListItem.uuid }; break; case "hysteria": case "hysteria2": // 后端的 "hysteria" 实际上是 Hysteria2 协议 final securityConfig = json["security_config"] as Map? ?? {}; config = { "type": "hysteria2", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": json["port"], "password": nodeListItem.uuid, "up_mbps": 100, "down_mbps": 100, "obfs": { "type": "salamander", "password": json["obfs_password"] ?? nodeListItem.uuid }, "tls": { "enabled": true, "server_name": securityConfig["sni"] ?? "", "insecure": securityConfig["allow_insecure"] ?? true } }; break; case "trojan": final securityConfig = json["security_config"] as Map? ?? {}; // 智能设置 server_name String serverName = securityConfig["sni"] ?? ""; if (serverName.isEmpty) { // 如果没有配置 SNI,使用服务器地址 serverName = nodeListItem.serverAddr; } config = { "type": "trojan", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": json["port"], "password": nodeListItem.uuid, "tls": { "enabled": json["security"] == "tls", "server_name": serverName, "insecure": securityConfig["allow_insecure"] ?? true, "utls": {"enabled": true, "fingerprint": "chrome"} } }; break; } // 检查 relayNode 是否为 JSON 字符串并解析 if (nodeListItem.relayNode.isNotEmpty && nodeListItem.relayMode != "none") { final relayNodeJson = jsonDecode(nodeListItem.relayNode); if (relayNodeJson is List && nodeListItem.relayMode != "none") { // 随机选择一个元素 final randomNode = (relayNodeJson..shuffle()).first; config["server"] = randomNode["host"]; // 提取 host config["server_port"] = randomNode["port"]; // 提取 port } } // 解析配置 } /// 构建传输配置 Map _buildTransport(Map json) { final transportType = json["transport"] as String?; final transportConfig = json["transport_config"] as Map? ?? {}; switch (transportType) { case "ws": return { "type": "ws", "path": transportConfig["path"] ?? "/", if (transportConfig["host"] != null) "headers": {"Host": transportConfig["host"]} }; case "grpc": return { "type": "grpc", "service_name": transportConfig["service_name"] ?? "" }; case "http": return { "type": "http", "host": [transportConfig["host"] ?? ""], "path": transportConfig["path"] ?? "/" }; default: return {}; } } /// 直接从节点字段构建配置(新API格式) void _buildConfigFromFields(KrNodeListItem nodeListItem) { if (kDebugMode) { print('🔧 开始构建节点配置 - 协议: ${nodeListItem.protocol}, 名称: ${nodeListItem.name}'); } if (kDebugMode) { print('📋 节点详细信息:'); } if (kDebugMode) { print(' - serverAddr: ${nodeListItem.serverAddr}'); } if (kDebugMode) { print(' - port: ${nodeListItem.port}'); } if (kDebugMode) { print(' - uuid: ${nodeListItem.uuid}'); } if (kDebugMode) { print(' - method: ${nodeListItem.method}'); } if (kDebugMode) { print(' - config: ${nodeListItem.config}'); } if (kDebugMode) { print(' - protocols: ${nodeListItem.protocols}'); } // 🔧 尝试从 config 字段解析 transport 配置 Map? transportConfig; Map? securityConfig; // 🔧 关键修复:优先从 protocols 字段解析配置 if (nodeListItem.protocols.isNotEmpty) { try { final protocolsList = jsonDecode(nodeListItem.protocols) as List; if (kDebugMode) { print('📄 解析到 protocols 数组,共 ${protocolsList.length} 个协议'); } // 查找匹配当前协议类型的配置 Map? matchedProtocol; for (var protocol in protocolsList) { final protocolMap = protocol as Map; final type = protocolMap['type']?.toString().toLowerCase() ?? ''; final enable = protocolMap['enable'] ?? true; if (kDebugMode) { print(' 📋 协议: type=$type, enable=$enable'); } // 匹配协议类型(注意 hysteria 和 hysteria2 都匹配 hysteria) if (type == nodeListItem.protocol.toLowerCase() || (nodeListItem.protocol == 'hysteria' && type == 'hysteria2') || (nodeListItem.protocol == 'hysteria2' && type == 'hysteria')) { matchedProtocol = protocolMap; if (kDebugMode) { print(' ✅ 找到匹配的协议配置: $type'); } break; } } if (matchedProtocol != null) { // 提取 transport 配置 if (matchedProtocol['network'] != null || matchedProtocol['transport'] != null) { final network = matchedProtocol['network'] ?? matchedProtocol['transport']; if (kDebugMode) { print(' 📡 传输协议: $network'); } if (network == 'ws' || network == 'websocket') { transportConfig = { 'type': 'ws', 'path': matchedProtocol['ws_path'] ?? matchedProtocol['path'] ?? '/', }; final host = matchedProtocol['ws_host'] ?? matchedProtocol['host']; if (host != null && host.toString().isNotEmpty) { transportConfig['headers'] = {'Host': host.toString()}; } if (kDebugMode) { print(' ✅ WebSocket transport: $transportConfig'); } } else if (network == 'grpc') { transportConfig = { 'type': 'grpc', 'service_name': matchedProtocol['grpc_service_name'] ?? matchedProtocol['service_name'] ?? '', }; if (kDebugMode) { print(' ✅ gRPC transport: $transportConfig'); } } else if (network == 'http' || network == 'h2') { transportConfig = { 'type': 'http', 'host': [matchedProtocol['http_host'] ?? matchedProtocol['host'] ?? ''], 'path': matchedProtocol['http_path'] ?? matchedProtocol['path'] ?? '/', }; if (kDebugMode) { print(' ✅ HTTP transport: $transportConfig'); } } } // 提取 security 配置 if (matchedProtocol['tls'] != null || matchedProtocol['security'] != null) { // 🔧 关键修复:读取 security 字段判断是否启用 TLS final security = matchedProtocol['security']?.toString().toLowerCase() ?? ''; final tlsEnabled = security == 'tls' || security == 'reality'; securityConfig = { 'tls_enabled': tlsEnabled, // ← 新增:记录 TLS 是否启用 'sni': matchedProtocol['sni'] ?? matchedProtocol['server_name'], 'allow_insecure': matchedProtocol['allow_insecure'] ?? matchedProtocol['insecure'] ?? true, 'fingerprint': matchedProtocol['fingerprint'] ?? 'chrome', }; if (kDebugMode) { print(' ✅ Security config: security=$security, tls_enabled=$tlsEnabled, config=$securityConfig'); } } } } catch (e) { if (kDebugMode) { print('⚠️ 解析 protocols 字段失败: $e'); } } } // 兜底:尝试从 config 字段解析(旧API格式) if (transportConfig == null && nodeListItem.config.isNotEmpty) { try { final configJson = jsonDecode(nodeListItem.config) as Map; if (kDebugMode) { print('📄 解析到 config JSON: $configJson'); } // 提取 transport 配置 if (configJson['transport'] != null && configJson['transport'] != 'tcp') { transportConfig = _buildTransport(configJson); if (kDebugMode) { print('✅ 从 config 找到 transport 配置: $transportConfig'); } } // 提取 security_config if (configJson['security_config'] != null) { securityConfig = configJson['security_config'] as Map; if (kDebugMode) { print('✅ 从 config 找到 security_config: $securityConfig'); } } } catch (e) { if (kDebugMode) { print('⚠️ 解析 config 字段失败: $e'); } } } switch (nodeListItem.protocol) { case "shadowsocks": // 优先使用 protocols 解析出来的 cipher,其次是 method 字段,最后才是默认值 String finalMethod = nodeListItem.method.isNotEmpty ? nodeListItem.method : "2022-blake3-aes-256-gcm"; config = { "type": "shadowsocks", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": nodeListItem.port, "method": finalMethod, "password": nodeListItem.uuid }; if (kDebugMode) { print('✅ Shadowsocks 节点配置构建成功: ${nodeListItem.name}'); } if (kDebugMode) { print('📄 使用加密方法: $finalMethod'); } if (kDebugMode) { print('📄 完整配置: $config'); } break; case "vless": // 判断是否为域名(非IP地址) final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') .hasMatch(nodeListItem.serverAddr); // 🔧 优先使用 security_config 中的 SNI String serverName = nodeListItem.serverAddr; if (securityConfig != null && securityConfig['sni'] != null && securityConfig['sni'].toString().isNotEmpty) { serverName = securityConfig['sni'].toString(); } // 🔧 关键修复:根据 security_config 判断是否启用 TLS final bool vlessTlsEnabled = securityConfig?['tls_enabled'] ?? false; if (kDebugMode) { print('🔐 VLESS TLS 状态: enabled=$vlessTlsEnabled'); } config = { "type": "vless", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": nodeListItem.port, "uuid": nodeListItem.uuid, if (transportConfig != null) "transport": transportConfig, if (vlessTlsEnabled) "tls": { "enabled": true, if (isDomain) "server_name": serverName, "insecure": securityConfig?['allow_insecure'] ?? true, "utls": { "enabled": true, "fingerprint": securityConfig?['fingerprint'] ?? "chrome" } } }; if (kDebugMode) { print('✅ VLESS 节点配置构建成功: ${nodeListItem.name}'); } if (kDebugMode) { print('📄 完整配置: $config'); } break; case "vmess": // 判断是否为域名(非IP地址) final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') .hasMatch(nodeListItem.serverAddr); // 🔧 优先使用 security_config 中的 SNI String serverName = nodeListItem.serverAddr; if (securityConfig != null && securityConfig['sni'] != null && securityConfig['sni'].toString().isNotEmpty) { serverName = securityConfig['sni'].toString(); } // 🔧 关键修复:根据 security_config 判断是否启用 TLS final bool tlsEnabled = securityConfig?['tls_enabled'] ?? false; if (kDebugMode) { print('🔐 TLS 状态: enabled=$tlsEnabled'); } config = { "type": "vmess", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": nodeListItem.port, "uuid": nodeListItem.uuid, "alter_id": 0, "security": "auto", if (transportConfig != null) "transport": transportConfig, if (tlsEnabled) "tls": { "enabled": true, if (isDomain) "server_name": serverName, "insecure": securityConfig?['allow_insecure'] ?? true, "utls": { "enabled": true, "fingerprint": securityConfig?['fingerprint'] ?? "chrome" } } }; if (kDebugMode) { print('✅ VMess 节点配置构建成功: ${nodeListItem.name}'); } if (kDebugMode) { print('📄 完整配置: $config'); } break; case "trojan": // 判断是否为域名(非IP地址) final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') .hasMatch(nodeListItem.serverAddr); // 🔧 优先使用 security_config 中的 SNI String serverName = nodeListItem.serverAddr; if (securityConfig != null && securityConfig['sni'] != null && securityConfig['sni'].toString().isNotEmpty) { serverName = securityConfig['sni'].toString(); } config = { "type": "trojan", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": nodeListItem.port, "password": nodeListItem.uuid, if (transportConfig != null) "transport": transportConfig, "tls": { "enabled": true, if (isDomain) "server_name": serverName, "insecure": securityConfig?['allow_insecure'] ?? true, "utls": { "enabled": true, "fingerprint": securityConfig?['fingerprint'] ?? "chrome" } } }; if (kDebugMode) { print('✅ Trojan 节点配置构建成功: ${nodeListItem.name}'); } if (kDebugMode) { print('📄 完整配置: $config'); } break; case "hysteria": case "hysteria2": // 后端的 "hysteria" 实际上是 Hysteria2 协议 if (kDebugMode) { print('🔍 构建 Hysteria2 节点: ${nodeListItem.name}'); } if (kDebugMode) { print(' - serverAddr: ${nodeListItem.serverAddr}'); } if (kDebugMode) { print(' - port: ${nodeListItem.port}'); } if (kDebugMode) { print(' - uuid: ${nodeListItem.uuid}'); } //判断是否为域名 final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') .hasMatch(nodeListItem.serverAddr); config = { "type": "hysteria2", "tag": nodeListItem.name, "server": nodeListItem.serverAddr, "server_port": nodeListItem.port, "password": nodeListItem.uuid, "tls": { "enabled": true, if (isDomain) "server_name": nodeListItem.serverAddr, } }; if (kDebugMode) { print('✅ Hysteria2 节点配置构建成功'); } if (kDebugMode) { print('📄 完整配置: ${jsonEncode(config)}'); } break; default: if (kDebugMode) { print('⚠️ 不支持的协议类型: ${nodeListItem.protocol}'); } config = {}; } } }