feat: debug
Some checks failed
Build Android APK / 编译 libcore.aar (push) Has been cancelled
Build Android APK / 编译 Android APK (release) (push) Has been cancelled
Build Android APK / 创建 GitHub Release (push) Has been cancelled
Build Multi-Platform / 编译 libcore (iOS/tvOS) (push) Has been cancelled
Build Windows / 编译 libcore (Windows) (push) Has been cancelled
Build Windows / build (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Android) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Windows) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (macOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Linux) (push) Has been cancelled
Build Multi-Platform / 构建 Android APK (push) Has been cancelled
Build Multi-Platform / 构建 Windows (push) Has been cancelled
Build Multi-Platform / 构建 macOS (push) Has been cancelled
Build Multi-Platform / 构建 Linux (push) Has been cancelled
Build Multi-Platform / 构建 iOS (push) Has been cancelled
Build Multi-Platform / 创建 Release (push) Has been cancelled
Some checks failed
Build Android APK / 编译 libcore.aar (push) Has been cancelled
Build Android APK / 编译 Android APK (release) (push) Has been cancelled
Build Android APK / 创建 GitHub Release (push) Has been cancelled
Build Multi-Platform / 编译 libcore (iOS/tvOS) (push) Has been cancelled
Build Windows / 编译 libcore (Windows) (push) Has been cancelled
Build Windows / build (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Android) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Windows) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (macOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Linux) (push) Has been cancelled
Build Multi-Platform / 构建 Android APK (push) Has been cancelled
Build Multi-Platform / 构建 Windows (push) Has been cancelled
Build Multi-Platform / 构建 macOS (push) Has been cancelled
Build Multi-Platform / 构建 Linux (push) Has been cancelled
Build Multi-Platform / 构建 iOS (push) Has been cancelled
Build Multi-Platform / 创建 Release (push) Has been cancelled
This commit is contained in:
parent
1e7175edf5
commit
765b45c0fc
@ -25,67 +25,20 @@ class HINodeListController extends GetxController {
|
||||
|
||||
/// 更新连接类型
|
||||
void kr_updateConnectionType(KRConnectionType type) {
|
||||
KRSingBoxImp.instance.kr_updateConnectionType(type);
|
||||
KRLogUtil.kr_i('连接类型已更新为: $type', tag: 'HINodeListController');
|
||||
|
||||
if (KRSingBoxImp().kr_connectionType.value != type) {
|
||||
KRSingBoxImp.instance.kr_updateConnectionType(type);
|
||||
KRLogUtil.kr_i('连接类型已更新为: $type', tag: 'HINodeListController');
|
||||
// 这里可以添加其他需要的逻辑
|
||||
}
|
||||
|
||||
// 如果当前有选择的国家,触发重选检查
|
||||
if (homeController.currentSelectedCountry.isNotEmpty) {
|
||||
KRLogUtil.kr_i('连接类型更新后,检查是否需要重选节点', tag: 'HINodeListController');
|
||||
// 延迟一下让连接类型更新完成
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
homeController.checkCountryReselection(KRSingBoxImp.instance.kr_activeGroups);
|
||||
// homeController.checkCountryReselection(KRSingBoxImp.instance.kr_activeGroups);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取当前国家内的有效节点标签列表
|
||||
List<String> getValidNodesInCurrentCountry() {
|
||||
final country = homeController.currentSelectedCountry.value;
|
||||
if (country.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final countryGroup = kr_subscribeService.countryOutboundList
|
||||
.firstWhereOrNull((group) => group.country == country);
|
||||
|
||||
if (countryGroup == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return countryGroup.outboundList
|
||||
.where((node) => node.urlTestDelay.value < 65535 && node.urlTestDelay.value > 0)
|
||||
.map((node) => node.tag)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 手动触发当前国家内的重选
|
||||
void manualReselection() {
|
||||
final country = homeController.currentSelectedCountry.value;
|
||||
if (country.isEmpty) {
|
||||
KRLogUtil.kr_w('没有选择国家,无法进行重选', tag: 'HINodeListController');
|
||||
return;
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('用户手动触发国家内重选', tag: 'HINodeListController');
|
||||
homeController.performCountryReselection(country);
|
||||
}
|
||||
|
||||
/// 获取当前国家内节点的延迟统计(委托给homeController)
|
||||
Map<String, dynamic> getCurrentCountryLatencyStats() {
|
||||
return homeController.getCurrentCountryNodeStats();
|
||||
}
|
||||
|
||||
/// 启用/禁用动态重选功能(委托给homeController)
|
||||
void setDynamicReselectionEnabled(bool enabled) {
|
||||
homeController.setCountryReselectionEnabled(enabled);
|
||||
}
|
||||
|
||||
/// 获取动态重选状态信息
|
||||
Map<String, dynamic> getDynamicReselectionStatus() {
|
||||
return {
|
||||
'enabled': homeController.isCountryReselectionEnabled.value,
|
||||
'currentCountry': homeController.currentSelectedCountry.value,
|
||||
'latencyThreshold': homeController.countryReselectionLatencyThreshold,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,19 +42,22 @@ class HINodeListView extends GetView<HINodeListController> {
|
||||
/// 获取分组内最快节点的延迟值(单位:ms)
|
||||
/// 如果列表为空,返回 0
|
||||
int getFastestNodeDelay(
|
||||
HINodeListController controller, List<KROutboundItem> outboundList) {
|
||||
HINodeListController controller,
|
||||
List<KROutboundItem> outboundList,
|
||||
) {
|
||||
if (outboundList.isEmpty) return 0;
|
||||
|
||||
int fastestDelay = _getDisplayDelay(controller, outboundList.first);
|
||||
// 过滤掉不可用节点(延迟标记为 65535 或负数)
|
||||
final validNodes = outboundList.where((node) {
|
||||
final delay = node.urlTestDelay.value;
|
||||
return delay > 0 && delay < 65535;
|
||||
}).toList();
|
||||
|
||||
for (final item in outboundList.skip(1)) {
|
||||
final delay = _getDisplayDelay(controller, item);
|
||||
if (delay < fastestDelay) {
|
||||
fastestDelay = delay;
|
||||
}
|
||||
}
|
||||
if (validNodes.isEmpty) return 0;
|
||||
|
||||
return fastestDelay;
|
||||
// 返回最小延迟值
|
||||
validNodes.sort((a, b) => a.urlTestDelay.value.compareTo(b.urlTestDelay.value));
|
||||
return validNodes.first.urlTestDelay.value;
|
||||
}
|
||||
|
||||
/// 找出延迟最低(最快)的节点对象
|
||||
@ -109,11 +112,19 @@ class HINodeListView extends GetView<HINodeListController> {
|
||||
_buildEmptyListPlaceholder(context, AppTranslations.kr_home.noRegions)
|
||||
else ...[
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.homeController.kr_selectNode('auto');
|
||||
controller.homeController.kr_currentListStatus.value =
|
||||
KRHomeViewsListStatus.kr_none;
|
||||
controller.homeController.kr_coutryText.value = 'auto';
|
||||
// 🔧 修复:改为 async,等待节点切换完成后再关闭列表
|
||||
onTap: () async {
|
||||
try {
|
||||
final success =
|
||||
await controller.homeController.kr_performNodeSwitch('auto');
|
||||
if (success) {
|
||||
controller.homeController.kr_currentListStatus.value =
|
||||
KRHomeViewsListStatus.kr_none;
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('Auto选项切换异常: $e',
|
||||
tag: 'NodeListView');
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
@ -189,14 +200,7 @@ class HINodeListView extends GetView<HINodeListController> {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
// 自动选择这个国家下的节点延迟中最快的
|
||||
final item = findFastestNode(country.outboundList);
|
||||
KRLogUtil.kr_i(item.tag);
|
||||
print('item${item.toString()}');
|
||||
controller.homeController.kr_selectNode(item.tag);
|
||||
controller.homeController.kr_currentListStatus.value =
|
||||
KRHomeViewsListStatus.kr_none;
|
||||
controller.homeController.kr_coutryText.value = country.country;
|
||||
|
||||
controller.homeController.onCountrySelected(country.country);
|
||||
},
|
||||
child: _kr_buildCountryListItem(context, country: country),
|
||||
);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
@ -115,7 +116,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
// 国家内节点重选相关属性
|
||||
final RxString currentSelectedCountry = ''.obs;
|
||||
final RxBool isCountryReselectionEnabled = true.obs;
|
||||
final int countryReselectionLatencyThreshold = 3000; // 延迟阈值(毫秒)
|
||||
|
||||
// 添加一个方法来切换状态
|
||||
@ -601,8 +601,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
// 强制更新UI
|
||||
update();
|
||||
|
||||
// 检查是否需要进行国家内节点重选
|
||||
_checkCountryReselection(value);
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('处理活动组时发生错误: $e', tag: 'HomeController');
|
||||
// 🔧 修复:发生错误时,如果已连接,设置延迟为0
|
||||
@ -632,34 +630,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
kr_updateMarkers(updateTags);
|
||||
}
|
||||
});
|
||||
|
||||
// 语言变化监听
|
||||
/**
|
||||
ever(KRLanguageUtils.kr_language, (_) {
|
||||
KRLogUtil.kr_i('🌐 语言变化,更新连接文本', tag: 'HomeController');
|
||||
kr_connectText.value = "";
|
||||
|
||||
switch (KRSingBoxImp.instance.kr_status.value) {
|
||||
case SingboxStopped():
|
||||
kr_connectText.value = AppTranslations.kr_home.disconnected;
|
||||
kr_currentIp.value = "--";
|
||||
kr_currentProtocol.value = "--";
|
||||
break;
|
||||
case SingboxStarting():
|
||||
kr_connectText.value = AppTranslations.kr_home.connecting;
|
||||
break;
|
||||
case SingboxStarted():
|
||||
kr_connectText.value = AppTranslations.kr_home.connected;
|
||||
break;
|
||||
case SingboxStopping():
|
||||
kr_connectText.value = AppTranslations.kr_home.disconnecting;
|
||||
break;
|
||||
}
|
||||
|
||||
// 强制更新UI
|
||||
update();
|
||||
});
|
||||
***/
|
||||
}
|
||||
|
||||
/// 🔧 重构: 参考 hiddify-app 的 toggleConnection 实现
|
||||
@ -946,79 +916,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
return node.urlTestDelay.value < 65535 && node.urlTestDelay.value > 0;
|
||||
}
|
||||
|
||||
/// 检查是否需要进行国家内节点重选
|
||||
void _checkCountryReselection(List<dynamic> activeGroups) {
|
||||
// 如果未启用国家内重选功能,直接返回
|
||||
if (!isCountryReselectionEnabled.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果未连接,直接返回
|
||||
if (!kr_isConnected.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有选择国家,直接返回
|
||||
if (currentSelectedCountry.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取当前节点信息
|
||||
final currentNodeInfo = kr_getRealConnectedNodeInfo();
|
||||
final currentDelay = currentNodeInfo['delay'] as int;
|
||||
|
||||
// 检查当前节点延迟是否超过阈值
|
||||
if (currentDelay > 0 && currentDelay < countryReselectionLatencyThreshold) {
|
||||
// 延迟正常,无需重选
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果延迟超过阈值或无效,尝试在当前国家内重选
|
||||
if (currentDelay >= countryReselectionLatencyThreshold || currentDelay <= 0) {
|
||||
KRLogUtil.kr_w('🔄 当前节点延迟过高(${currentDelay}ms),尝试国家内重选', tag: 'HomeController');
|
||||
_performCountryReselection(currentSelectedCountry.value);
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('检查国家内重选时出错: $e', tag: 'HomeController');
|
||||
}
|
||||
}
|
||||
|
||||
/// 执行国家内节点重选
|
||||
void _performCountryReselection(String country) {
|
||||
try {
|
||||
// 获取指定国家的所有节点
|
||||
final countryNodes = kr_subscribeService.allList
|
||||
.where((node) => node.country == country && node.tag != 'auto')
|
||||
.toList();
|
||||
|
||||
if (countryNodes.isEmpty) {
|
||||
KRLogUtil.kr_w('⚠️ 国家 $country 内没有可用节点', tag: 'HomeController');
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到延迟最小的有效节点
|
||||
String? bestNode;
|
||||
int minDelay = 65535;
|
||||
|
||||
for (var node in countryNodes) {
|
||||
final delay = node.urlTestDelay.value;
|
||||
if (delay > 0 && delay < 65535 && delay < minDelay) {
|
||||
minDelay = delay;
|
||||
bestNode = node.tag;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestNode != null && bestNode != kr_cutSeletedTag.value) {
|
||||
KRLogUtil.kr_i('🎯 国家内重选: $bestNode (${minDelay}ms)', tag: 'HomeController');
|
||||
kr_selectNode(bestNode);
|
||||
} else {
|
||||
KRLogUtil.kr_w('⚠️ 国家 $country 内没有更好的节点可选', tag: 'HomeController');
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('执行国家内重选时出错: $e', tag: 'HomeController');
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置当前选择的国家(由hi_node_list_controller调用)
|
||||
void setCurrentSelectedCountry(String country) {
|
||||
@ -1026,66 +923,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
KRLogUtil.kr_i('🌍 设置当前选择国家: $country', tag: 'HomeController');
|
||||
}
|
||||
|
||||
/// 启用/禁用国家内重选功能
|
||||
void setCountryReselectionEnabled(bool enabled) {
|
||||
isCountryReselectionEnabled.value = enabled;
|
||||
KRLogUtil.kr_i('🔄 国家内重选功能已${enabled ? "启用" : "禁用"}', tag: 'HomeController');
|
||||
}
|
||||
|
||||
/// 获取当前国家内的节点统计信息
|
||||
Map<String, dynamic> getCurrentCountryNodeStats() {
|
||||
if (currentSelectedCountry.isEmpty) {
|
||||
return {'error': '没有选择国家'};
|
||||
}
|
||||
|
||||
final countryNodes = kr_subscribeService.allList
|
||||
.where((node) => node.country == currentSelectedCountry.value && node.tag != 'auto')
|
||||
.toList();
|
||||
|
||||
if (countryNodes.isEmpty) {
|
||||
return {'error': '国家内没有节点'};
|
||||
}
|
||||
|
||||
List<int> validDelays = [];
|
||||
int totalNodes = countryNodes.length;
|
||||
int validNodes = 0;
|
||||
int minDelay = 65535;
|
||||
int maxDelay = 0;
|
||||
String? fastestNode;
|
||||
String? slowestNode;
|
||||
|
||||
for (var node in countryNodes) {
|
||||
final delay = node.urlTestDelay.value;
|
||||
if (delay > 0 && delay < 65535) {
|
||||
validDelays.add(delay);
|
||||
validNodes++;
|
||||
|
||||
if (delay < minDelay) {
|
||||
minDelay = delay;
|
||||
fastestNode = node.tag;
|
||||
}
|
||||
|
||||
if (delay > maxDelay) {
|
||||
maxDelay = delay;
|
||||
slowestNode = node.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double avgDelay = validDelays.isEmpty ? 0 : validDelays.reduce((a, b) => a + b) / validDelays.length;
|
||||
|
||||
return {
|
||||
'country': currentSelectedCountry.value,
|
||||
'totalNodes': totalNodes,
|
||||
'validNodes': validNodes,
|
||||
'minDelay': minDelay == 65535 ? 0 : minDelay,
|
||||
'maxDelay': maxDelay,
|
||||
'avgDelay': avgDelay.round(),
|
||||
'fastestNode': fastestNode,
|
||||
'slowestNode': slowestNode,
|
||||
'validDelays': validDelays,
|
||||
};
|
||||
}
|
||||
|
||||
/// 更新自动模式延迟
|
||||
void _kr_updateAutoLatency(dynamic element) {
|
||||
@ -1138,8 +975,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
if (!kr_isConnected.value) {
|
||||
KRLogUtil.kr_i('📴 VPN未连接,只更新UI变量: $tag', tag: 'HomeController');
|
||||
kr_cutSeletedTag.value = tag;
|
||||
kr_updateConnectionInfo();
|
||||
kr_moveToSelectedNode();
|
||||
// kr_moveToSelectedNode();
|
||||
|
||||
// 🔧 修复:保存节点选择以便VPN启动时应用
|
||||
KRLogUtil.kr_i('💾 保存节点选择以便稍后应用: $tag', tag: 'HomeController');
|
||||
@ -1215,6 +1051,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onCountrySelected(String countryTag) async {
|
||||
await KRSingBoxImp.instance.kr_selectCountry(countryTag);
|
||||
KRCommonUtil.kr_showToast('已切换到 $countryTag 节点组');
|
||||
}
|
||||
|
||||
/// 🔧 修复:简化的 kr_selectNode 方法
|
||||
/// 现在只是委托给新的 kr_performNodeSwitch 方法
|
||||
/// 为了保持向后兼容,保留此方法但改为调用新方法
|
||||
@ -1309,7 +1150,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
// auto 模式下,获取 urltest 组的实际连接节点
|
||||
print('当前活动组----${KRSingBoxImp.instance.kr_activeGroups.length}');
|
||||
for (var group in KRSingBoxImp.instance.kr_activeGroups) {
|
||||
print('当前活动组----$group}');
|
||||
if (group.type == ProxyType.urltest) {
|
||||
final selectedNode = group.selected;
|
||||
final node = kr_subscribeService.keyList[selectedNode];
|
||||
@ -1320,6 +1163,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
};
|
||||
}
|
||||
}
|
||||
print('hhhhhh${kr_subscribeService.keyList}', );
|
||||
|
||||
// 如果没有找到 urltest 组,返回默认值
|
||||
return {
|
||||
@ -1344,7 +1188,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
/// 获取真实连接的节点国家
|
||||
String kr_getRealConnectedNodeCountry() {
|
||||
final info = kr_getRealConnectedNodeInfo();
|
||||
final delay = info['delay'];
|
||||
final delay = kr_currentNodeLatency.value;
|
||||
final country = kr_getCountryFullName(info['country']);
|
||||
if (delay == -2) {
|
||||
return '--';
|
||||
@ -1722,45 +1566,75 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
/// 未连接状态下的延迟测试(界面显示随机延迟,不影响真实逻辑)
|
||||
Future<void> _kr_testSingleNode(dynamic item) async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
try {
|
||||
// 解析地址和端口
|
||||
String address = item.serverAddr;
|
||||
int port = 443; // 默认端口
|
||||
|
||||
// 如果 serverAddr 带端口
|
||||
if (item.serverAddr.contains(':')) {
|
||||
final parts = item.serverAddr.split(':');
|
||||
address = parts[0];
|
||||
port = int.tryParse(parts[1]) ?? 443;
|
||||
} else if (item.config['server_port'] != null) {
|
||||
port = item.config['server_port'];
|
||||
}
|
||||
|
||||
// TCP 测试连接
|
||||
final socket = await Socket.connect(
|
||||
address,
|
||||
port,
|
||||
timeout: const Duration(seconds: 8),
|
||||
);
|
||||
|
||||
final delay = stopwatch.elapsedMilliseconds;
|
||||
socket.destroy();
|
||||
|
||||
// 设置延迟阈值:超过5秒认为不可用
|
||||
if (delay > 5000) {
|
||||
item.urlTestDelay.value = 65535;
|
||||
} else {
|
||||
item.urlTestDelay.value = delay;
|
||||
}
|
||||
|
||||
print('✅ 节点 ${item.tag} 测试完成,延迟: ${item.urlTestDelay.value}ms');
|
||||
|
||||
} catch (e) {
|
||||
// 连接失败
|
||||
item.urlTestDelay.value = 65535;
|
||||
print('⚠️ 节点 ${item.tag} 测试失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 未连接状态下的延迟测试(使用本机网络真实测速)
|
||||
Future<void> _kr_testLatencyWithoutVpn() async {
|
||||
kr_isLatency.value = true;
|
||||
try {
|
||||
KRLogUtil.kr_i(
|
||||
'🔌 开始未连接状态延迟测试(界面显示随机延迟)', tag: 'HomeController');
|
||||
KRLogUtil.kr_i(
|
||||
'📊 当前连接状态: ${kr_isConnected.value}', tag: 'HomeController');
|
||||
KRLogUtil.kr_i('🎲 界面将显示30ms-100ms的随机延迟,不影响其他逻辑',
|
||||
tag: 'HomeController');
|
||||
|
||||
// 获取所有非auto节点
|
||||
try {
|
||||
KRLogUtil.kr_i('🔌 开始未连接状态延迟测试(真实测速)', tag: 'HomeController');
|
||||
KRLogUtil.kr_i('📊 当前连接状态: ${kr_isConnected.value}', tag: 'HomeController');
|
||||
|
||||
// 获取所有非 auto 节点
|
||||
final testableNodes = kr_subscribeService.allList
|
||||
.where((item) => item.tag != 'auto')
|
||||
.toList();
|
||||
|
||||
KRLogUtil.kr_i(
|
||||
'📋 找到 ${testableNodes.length} 个可测试节点', tag: 'HomeController');
|
||||
KRLogUtil.kr_i('📋 找到 ${testableNodes.length} 个可测试节点', tag: 'HomeController');
|
||||
|
||||
if (testableNodes.isEmpty) {
|
||||
KRLogUtil.kr_w('⚠️ 没有可测试的节点', tag: 'HomeController');
|
||||
return;
|
||||
}
|
||||
|
||||
// 不修改真实的 urlTestDelay,让界面层处理随机延迟显示
|
||||
KRLogUtil.kr_i(
|
||||
'✅ 延迟显示将由界面层处理,不影响节点选择逻辑', tag: 'NodeTest');
|
||||
// 依次测试每个节点延迟
|
||||
for (var node in testableNodes) {
|
||||
await _kr_testSingleNode(node); // 真实测速
|
||||
KRLogUtil.kr_i('节点 ${node.tag} 延迟: ${node.urlTestDelay.value}ms', tag: 'HomeController');
|
||||
}
|
||||
|
||||
// 统计测试结果
|
||||
final successCount = testableNodes
|
||||
.where((item) => item.urlTestDelay.value < 65535)
|
||||
.length;
|
||||
final failCount = testableNodes.length - successCount;
|
||||
|
||||
KRLogUtil.kr_i('✅ 本机网络延迟测试完成', tag: 'HomeController');
|
||||
KRLogUtil.kr_i('📊 测试结果: 成功 $successCount 个,失败 $failCount 个',
|
||||
tag: 'HomeController');
|
||||
|
||||
// 显示前几个节点的延迟结果
|
||||
// 测试完成后,按延迟排序,方便界面展示
|
||||
final sortedNodes = testableNodes
|
||||
.where((item) => item.urlTestDelay.value < 65535)
|
||||
.toList()
|
||||
@ -1770,11 +1644,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
KRLogUtil.kr_i('🏆 延迟最低的前3个节点:', tag: 'HomeController');
|
||||
for (int i = 0; i < 3 && i < sortedNodes.length; i++) {
|
||||
final node = sortedNodes[i];
|
||||
KRLogUtil.kr_i(
|
||||
' ${i + 1}. ${node.tag}: ${node.urlTestDelay.value}ms',
|
||||
tag: 'HomeController');
|
||||
KRLogUtil.kr_i(' ${i + 1}. ${node.tag}: ${node.urlTestDelay.value}ms', tag: 'HomeController');
|
||||
}
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('✅ 本机网络延迟测试完成', tag: 'HomeController');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('❌ 本机网络延迟测试过程出错: $e', tag: 'HomeController');
|
||||
} finally {
|
||||
@ -1782,7 +1656,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 开始连接计时
|
||||
void kr_startConnectionTimer() {
|
||||
kr_stopConnectionTimer();
|
||||
@ -1989,14 +1862,4 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 公共方法:检查国家内重选(供其他控制器调用)
|
||||
void checkCountryReselection(List<dynamic> activeGroups) {
|
||||
_checkCountryReselection(activeGroups);
|
||||
}
|
||||
|
||||
/// 公共方法:执行国家内重选(供其他控制器调用)
|
||||
void performCountryReselection(String country) {
|
||||
_performCountryReselection(country);
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,6 +609,8 @@ class KRSingBoxImp {
|
||||
|
||||
/// 订阅分组数据流
|
||||
void _kr_subscribeToGroups() {
|
||||
KRLogUtil.kr_i('🛰 启动分组监听 watchActiveGroups / watchGroups', tag: 'SingBox');
|
||||
|
||||
// 取消之前的分组订阅
|
||||
for (var sub in _kr_subscriptions) {
|
||||
if (sub.hashCode.toString().contains('Groups')) {
|
||||
@ -1423,6 +1425,87 @@ class KRSingBoxImp {
|
||||
}
|
||||
}
|
||||
|
||||
/// 🌍 国家级节点选择
|
||||
/// 如果传入 'auto',则调用原有 kr_selectOutbound('auto')
|
||||
/// 否则根据国家名筛选该国节点,自动选择延迟最低的节点
|
||||
Future<void> kr_selectCountry(String country) async {
|
||||
KRLogUtil.kr_i('🌎 [v2.1] 开始选择国家: $country', tag: 'SingBox');
|
||||
|
||||
if (country == 'auto') {
|
||||
KRLogUtil.kr_i('🌀 国家为 auto,执行自动节点选择逻辑', tag: 'SingBox');
|
||||
await kr_selectOutbound('auto');
|
||||
return;
|
||||
}
|
||||
|
||||
if (kr_activeGroups.isEmpty) {
|
||||
KRLogUtil.kr_w('⚠️ kr_activeGroups 当前为空,无法进行国家选择', tag: 'SingBox');
|
||||
return;
|
||||
}
|
||||
|
||||
/*final selectGroup = kr_activeGroups.firstWhere(
|
||||
(group) => group.tag == 'select',
|
||||
orElse: () => throw Exception('未找到 "select" 组'),
|
||||
);
|
||||
|
||||
final countryNodes = selectGroup.items.where((item) {
|
||||
final nodeCountry = item.options?['country'] ?? '';
|
||||
return nodeCountry.toString().toLowerCase() == country.toLowerCase();
|
||||
}).toList();
|
||||
|
||||
if (countryNodes.isEmpty) {
|
||||
KRLogUtil.kr_w('⚠️ 未找到该国家的节点: $country', tag: 'SingBox');
|
||||
for (var item in selectGroup.items) {
|
||||
KRLogUtil.kr_d(
|
||||
' 可用节点: ${item.tag} (${item.options?['country'] ?? '未知'})',
|
||||
tag: 'SingBox',
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('🇨🇭 找到 ${countryNodes.length} 个属于 "$country" 的节点', tag: 'SingBox');
|
||||
|
||||
// 按延迟排序(无延迟则 9999)
|
||||
countryNodes.sort((a, b) =>
|
||||
(a.urlTestDelay ?? 9999).compareTo(b.urlTestDelay ?? 9999));
|
||||
|
||||
final fastestNode = countryNodes.first;
|
||||
final selectedTag = fastestNode.tag;
|
||||
final delay = fastestNode.urlTestDelay ?? -1;
|
||||
|
||||
KRLogUtil.kr_i('✅ 选中该国家最快节点: $selectedTag (${delay}ms)', tag: 'SingBox');
|
||||
|
||||
try {
|
||||
await KRSecureStorage().kr_saveData(key: 'selected_country', value: country);
|
||||
await KRSecureStorage().kr_saveData(key: _keySelectedNode, value: selectedTag);
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_w('⚠️ 保存国家/节点信息失败: $e', tag: 'SingBox');
|
||||
}
|
||||
|
||||
try {
|
||||
await _kr_ensureCommandClientInitialized();
|
||||
await _kr_selectOutboundWithRetry('select', selectedTag,
|
||||
maxAttempts: 3, initialDelay: 100);
|
||||
KRLogUtil.kr_i('✅ 国家内节点切换成功: $selectedTag', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('❌ 国家内节点选择失败: $e', tag: 'SingBox');
|
||||
rethrow;
|
||||
}
|
||||
|
||||
_nodeSelectionTimer?.cancel();
|
||||
KRLogUtil.kr_i('🔁 启动定时器防止节点被 auto 覆盖', tag: 'SingBox');
|
||||
_nodeSelectionTimer =
|
||||
Timer.periodic(const Duration(seconds: 20), (timer) async {
|
||||
try {
|
||||
await kr_singBox.selectOutbound('select', selectedTag).run();
|
||||
KRLogUtil.kr_d('🔁 定时确认国家内节点: $selectedTag', tag: 'SingBox');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_w('🔁 定时确认失败: $e', tag: 'SingBox');
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
/// 配合文件地址
|
||||
|
||||
Directory get directory =>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user