From a78b40c3396ea460146d20c7fb332f6c138d52aa Mon Sep 17 00:00:00 2001 From: speakeloudest Date: Sun, 9 Nov 2025 22:43:57 -0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 5 +- android/app/build.gradle | 4 +- .../controllers/kr_home_controller.dart | 20 +- .../controllers/kr_splash_controller.dart | 10 +- lib/app/utils/kr_latency_tester.dart | 196 ++++++++++-------- 5 files changed, 135 insertions(+), 100 deletions(-) diff --git a/.gitmodules b/.gitmodules index d0ce6bf..7355bf7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "libcore"] - path = libcore - url = https://github.com/hiddify/hiddify-next-core + path = libcore + url = https://github.com/hiddify/hiddify-next-core + branch = main diff --git a/android/app/build.gradle b/android/app/build.gradle index d3cb573..cc5255a 100755 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -105,8 +105,8 @@ android { debugSymbolLevel 'FULL' } // 禁用代码混淆和资源压缩,解决VPN连接问题 - minifyEnabled true - shrinkResources true + minifyEnabled false + shrinkResources false // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } diff --git a/lib/app/modules/kr_home/controllers/kr_home_controller.dart b/lib/app/modules/kr_home/controllers/kr_home_controller.dart index f7442a2..7766326 100755 --- a/lib/app/modules/kr_home/controllers/kr_home_controller.dart +++ b/lib/app/modules/kr_home/controllers/kr_home_controller.dart @@ -133,11 +133,21 @@ class KRHomeController extends GetxController with WidgetsBindingObserver { if (value != null) { isQuickConnectEnabled.value = value; // 保存闪连状态到本地存储 - await _storage.kr_saveBool(key: _quickConnectKey, value: value); + await _saveQuickConnectStatus(value); KRLogUtil.kr_i('闪连状态已更新: $value', tag: 'QuickConnect'); } } + // 保存闪连状态到本地存储 + Future _saveQuickConnectStatus(bool enabled) async { + try { + await _storage.kr_saveBool(key: _quickConnectKey, value: enabled); + KRLogUtil.kr_i('闪连状态已保存到本地存储: $enabled', tag: 'QuickConnect'); + } catch (e) { + KRLogUtil.kr_e('保存闪连状态失败: $e', tag: 'QuickConnect'); + } + } + // 从本地存储加载闪连状态 Future _loadQuickConnectStatus() async { try { @@ -1889,7 +1899,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver { } // 准备节点地址列表 - final nodeAddresses = >[]; + final nodeAddresses = []; // >[]; for (final node in testableNodes) { // 从节点配置中提取服务器地址和端口 @@ -1897,7 +1907,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver { String host = node.serverAddr; int port = 0; - // 尝试从config中获取端口 + /*// 尝试从config中获取端口 if (node.config.containsKey('server_port')) { port = node.config['server_port'] as int; } else if (node.config.containsKey('port')) { @@ -1914,7 +1924,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver { KRLogUtil.kr_w('⚠️ 节点 ${node.tag} 缺少地址或端口信息', tag: 'HomeController'); // 设置为失败 node.urlTestDelay.value = 65535; - } + }*/ } catch (e) { KRLogUtil.kr_e('❌ 解析节点 ${node.tag} 配置失败: $e', tag: 'HomeController'); node.urlTestDelay.value = 65535; @@ -1932,7 +1942,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver { final results = await KRLatencyTester.testMultipleNodes( nodes: nodeAddresses, concurrency: 10, // 每批10个并发 - timeout: 5000, // 超时时间5秒(毫秒) + timeout: const Duration(seconds: 5), ); // 更新节点延迟 diff --git a/lib/app/modules/kr_splash/controllers/kr_splash_controller.dart b/lib/app/modules/kr_splash/controllers/kr_splash_controller.dart index 6835ed5..d283597 100755 --- a/lib/app/modules/kr_splash/controllers/kr_splash_controller.dart +++ b/lib/app/modules/kr_splash/controllers/kr_splash_controller.dart @@ -285,7 +285,7 @@ class KRSplashController extends GetxController { KRLogUtil.kr_e('⏱️ 初始化超时: $e', tag: 'SplashController'); print('⏱️ 初始化超时,直接跳转到主页'); // 超时后直接跳转到主页,让用户可以手动重试 - // Get.offAllNamed(Routes.KR_MAIN); + // Get.offAllNamed(Routes.KR_HOME); HIDialog.show( message: '初始化超时,请检查网络或重试', confirmText: '重试', @@ -484,7 +484,7 @@ class KRSplashController extends GetxController { _initLog.logWarning('网络权限检查失败或超时,执行降级初始化', tag: 'Init'); KRLogUtil.kr_w('⚠️ 网络权限检查失败或超时,执行降级初始化', tag: 'SplashController'); await _executeMinimalInitialization(); - Get.offAllNamed(Routes.KR_MAIN); + Get.offAllNamed(Routes.KR_HOME); return; } @@ -493,7 +493,7 @@ class KRSplashController extends GetxController { _initLog.logError('网络权限检查异常,执行降级初始化', tag: 'Init', error: e); KRLogUtil.kr_w('⚠️ 网络权限检查异常: $e,执行降级初始化', tag: 'SplashController'); await _executeMinimalInitialization(); - Get.offAllNamed(Routes.KR_MAIN); + Get.offAllNamed(Routes.KR_HOME); return; } } else { @@ -582,7 +582,7 @@ class KRSplashController extends GetxController { _initLog.logError('启动页初始化异常,执行降级策略', tag: 'Continue', error: e); KRLogUtil.kr_w('⚠️ 启动页初始化异常,执行降级策略: $e', tag: 'SplashController'); await _executeMinimalInitialization(); - Get.offAllNamed(Routes.KR_MAIN); + Get.offAllNamed(Routes.KR_HOME); } } @@ -726,7 +726,7 @@ class KRSplashController extends GetxController { kr_isLoading.value = false; // 直接跳转到主页 - Get.offAllNamed(Routes.KR_MAIN); + Get.offAllNamed(Routes.KR_HOME); } /// 🔧 修复1.1:清理旧的本地存储数据(DEBUG模式专用) diff --git a/lib/app/utils/kr_latency_tester.dart b/lib/app/utils/kr_latency_tester.dart index 10e2f8a..385020f 100644 --- a/lib/app/utils/kr_latency_tester.dart +++ b/lib/app/utils/kr_latency_tester.dart @@ -1,127 +1,151 @@ import 'dart:io'; import 'dart:async'; -import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; +import 'kr_log_util.dart'; -/// 延迟测试工具类 -/// 提供真实的 TCP 连接延迟测试功能 +/// 真正的节点延迟测试工具 class KRLatencyTester { - /// 测试单个节点的延迟 - /// - /// 参数: - /// - host: 主机地址 - /// - port: 端口号 - /// - timeout: 超时时间(毫秒) - /// - /// 返回: - /// - 延迟时间(毫秒),如果失败返回 65535 - static Future testNode({ + /// TCP 连接测试延迟(真实测试) + /// 返回延迟毫秒数,失败返回 65535 + static Future testTcpLatency({ required String host, required int port, - int timeout = 5000, + Duration timeout = const Duration(seconds: 5), }) async { + Socket? socket; + final stopwatch = Stopwatch(); + try { - final stopwatch = Stopwatch()..start(); - - final socket = await Socket.connect( + KRLogUtil.kr_i('🔌 开始测试: $host:$port', tag: 'LatencyTester'); + + stopwatch.start(); + + // 尝试 TCP 连接 + socket = await Socket.connect( host, port, - timeout: Duration(milliseconds: timeout), - ).timeout(Duration(milliseconds: timeout)); - + timeout: timeout, + ); + stopwatch.stop(); - - // 立即关闭连接 - await socket.close(); - socket.destroy(); - + final latency = stopwatch.elapsedMilliseconds; - KRLogUtil.kr_i('✅ 延迟测试成功: $host:$port = ${latency}ms', tag: 'KRLatencyTester'); - + + KRLogUtil.kr_i('✅ 测试成功: $host:$port - ${latency}ms', tag: 'LatencyTester'); + return latency; + + } on SocketException catch (e) { + stopwatch.stop(); + KRLogUtil.kr_w('❌ 连接失败: $host:$port - ${e.message}', tag: 'LatencyTester'); + return 65535; + + } on TimeoutException catch (e) { + stopwatch.stop(); + KRLogUtil.kr_w('⏱️ 连接超时: $host:$port - $e', tag: 'LatencyTester'); + return 65535; + } catch (e) { - KRLogUtil.kr_w('❌ 延迟测试失败: $host:$port - $e', tag: 'KRLatencyTester'); - return 65535; // 测试失败返回最大值 + stopwatch.stop(); + KRLogUtil.kr_e('❌ 测试异常: $host:$port - $e', tag: 'LatencyTester'); + return 65535; + + } finally { + // 确保关闭连接 + try { + await socket?.close(); + } catch (e) { + // 忽略关闭错误 + } } } - /// 批量测试多个节点的延迟 - /// - /// 参数: - /// - nodes: 节点列表,格式为 [{"host": "example.com", "port": 443}] - /// - concurrency: 并发数量 - /// - timeout: 超时时间(毫秒) - /// - /// 返回: - /// - 测试结果映射,键为 "host:port",值为延迟时间 + /// 批量测试多个节点延迟(并发测试) + /// 返回 Map<节点tag, 延迟ms> static Future> testMultipleNodes({ required List> nodes, - int concurrency = 10, - int timeout = 5000, + int concurrency = 10, // 并发数 + Duration timeout = const Duration(seconds: 5), }) async { final results = {}; - final semaphore = Completer(); - var activeCount = 0; - var completedCount = 0; + final List>> batches = []; - KRLogUtil.kr_i('🚀 开始批量延迟测试,共 ${nodes.length} 个节点,并发数: $concurrency', tag: 'KRLatencyTester'); + // 分批处理 + for (int i = 0; i < nodes.length; i += concurrency) { + batches.add( + nodes.sublist(i, i + concurrency > nodes.length ? nodes.length : i + concurrency) + ); + } - Future processNode(MapEntry node) async { - try { - final host = node.value.address; - final port = node.value.port; - final key = node.key; - - final latency = await testNode( - host: host, - port: port, + KRLogUtil.kr_i('📊 开始批量测试: ${nodes.length} 个节点,分 ${batches.length} 批,每批 $concurrency 个', tag: 'LatencyTester'); + + int completedCount = 0; + + // 逐批测试 + for (int batchIndex = 0; batchIndex < batches.length; batchIndex++) { + final batch = batches[batchIndex]; + + KRLogUtil.kr_i('📦 测试第 ${batchIndex + 1}/${batches.length} 批(${batch.length} 个节点)', tag: 'LatencyTester'); + + // 并发测试当前批次 + final futures = batch.map((node) async { + final tag = node.key; + final address = node.value; + + final latency = await testTcpLatency( + host: address.host, + port: address.port, timeout: timeout, ); - - results[key] = latency; - } catch (e) { - results[node.key] = 65535; - KRLogUtil.kr_e('❌ 节点测试异常: ${node.key} - $e', tag: 'KRLatencyTester'); - } finally { + completedCount++; - activeCount--; - - if (completedCount >= nodes.length) { - semaphore.complete(); + + if (completedCount % 5 == 0 || completedCount == nodes.length) { + KRLogUtil.kr_i('📈 测试进度: $completedCount/${nodes.length}', tag: 'LatencyTester'); } - } - } - // 分批处理节点 - for (var i = 0; i < nodes.length; i += concurrency) { - final batch = nodes.skip(i).take(concurrency); - - for (final node in batch) { - activeCount++; - processNode(node); - } - + return MapEntry(tag, latency); + }).toList(); + // 等待当前批次完成 - if (i + concurrency < nodes.length) { - await Future.delayed(Duration(milliseconds: 100)); + final batchResults = await Future.wait(futures); + + // 收集结果 + for (final result in batchResults) { + results[result.key] = result.value; + } + } + + // 统计结果 + final successCount = results.values.where((latency) => latency < 65535).length; + final failCount = results.length - successCount; + + KRLogUtil.kr_i('✅ 批量测试完成', tag: 'LatencyTester'); + KRLogUtil.kr_i('📊 成功: $successCount, 失败: $failCount', tag: 'LatencyTester'); + + // 显示延迟最低的前3个 + final successNodes = results.entries + .where((e) => e.value < 65535) + .toList() + ..sort((a, b) => a.value.compareTo(b.value)); + + if (successNodes.isNotEmpty) { + KRLogUtil.kr_i('🏆 延迟最低的前3个节点:', tag: 'LatencyTester'); + for (int i = 0; i < 3 && i < successNodes.length; i++) { + KRLogUtil.kr_i(' ${i + 1}. ${successNodes[i].key}: ${successNodes[i].value}ms', tag: 'LatencyTester'); } } - // 等待所有任务完成 - await semaphore.future; - - KRLogUtil.kr_i('✅ 批量延迟测试完成,成功: ${results.length} 个', tag: 'KRLatencyTester'); return results; } } -/// Socket 地址类 -/// 表示网络地址和端口的组合 +/// 节点地址信息 class SocketAddress { - final String address; + final String host; final int port; - SocketAddress(this.address, this.port); + SocketAddress(this.host, this.port); @override - String toString() => '$address:$port'; -} \ No newline at end of file + String toString() => '$host:$port'; +}