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 fe6c65f..249c3c9 100755 --- a/lib/app/modules/kr_splash/controllers/kr_splash_controller.dart +++ b/lib/app/modules/kr_splash/controllers/kr_splash_controller.dart @@ -85,10 +85,10 @@ class KRSplashController extends GetxController { print('🧹 清理域名检测状态...'); KRDomain.kr_resetDomainState(); - // 🔧 P2优化:网站配置和设备登录在后台执行,不阻塞主流程 - print('🌐 启动后台任务:网站配置加载...'); - KRLogUtil.kr_i('🌐 后台任务:网站配置和设备登录', tag: 'SplashController'); - _kr_initSiteConfig(); // 不等待完成,在后台执行 + // 🔧 P2优化:网站配置不再后台执行,改为串行执行以确保域名验证完成 + // print('🌐 启动后台任务:网站配置加载...'); + // KRLogUtil.kr_i('🌐 后台任务:网站配置和设备登录', tag: 'SplashController'); + // _kr_initSiteConfig(); // 移至 _kr_continueInitialization 中串行执行 // 🔧 关键修复:先初始化日志收集器,再开始主流程 if (kDebugMode) { @@ -551,6 +551,14 @@ class KRSplashController extends GetxController { } // 网络检查完成后执行设备登录(始终支持) + + // 🔧 关键修复:在设备登录前先初始化站点配置,确保域名可用 + // 这样如果主域名不可用,initSiteConfig 会切换到备用域名 + // 后续的设备登录就能使用正确的域名 + _logStepTiming('开始站点配置初始化'); + await _kr_initSiteConfig(); + _logStepTiming('站点配置初始化完成'); + _logStepTiming('开始设备登录检查'); // 5️⃣ 执行设备登录 final success = await KRAppRunData.getInstance().kr_checkAndPerformDeviceLogin(); @@ -569,7 +577,12 @@ class KRSplashController extends GetxController { } _logStepTiming('设备登录检查完成'); - // 初始化配置 + // 初始化配置 (注意:这里再次调用init会导致重复,但AppConfig内部有防重, + // 不过为了逻辑清晰,既然上面已经调用了_kr_initSiteConfig(获取了KRSiteConfig), + // 下面AppConfig().initConfig主要是做AppConfig层面的配置加载,可能包含重复的请求。 + // 鉴于 AppConfig().initConfig 也会调用 API,为了保险起见, + // 我们可以让 AppConfig().initConfig 使用已经切换好的域名。) + _initLog.log('⚙️ 开始初始化应用配置(域名加载等)', tag: 'Continue'); KRLogUtil.kr_i('⚙️ 开始初始化应用配置...', tag: 'SplashController'); await AppConfig().initConfig( diff --git a/lib/app/services/kr_site_config_service.dart b/lib/app/services/kr_site_config_service.dart index 3c6908c..7f6d405 100644 --- a/lib/app/services/kr_site_config_service.dart +++ b/lib/app/services/kr_site_config_service.dart @@ -51,124 +51,134 @@ class KRSiteConfigService extends ChangeNotifier { /// 初始化站点配置 Future initialize() async { - try { - if (kDebugMode) { - print('🔧 KRSiteConfigService.initialize() 开始执行'); - } - KRLogUtil.kr_i('🔧 开始初始化网站配置', tag: 'KRSiteConfigService'); + int retryCount = 0; + const int maxRetries = 5; - // Debug 模式下使用固定地址 - final baseUrl = AppConfig().baseUrl; - if (kDebugMode) { - print('📍 baseUrl = $baseUrl'); - } - final url = '$baseUrl/v1/common/site/config'; - if (kDebugMode) { - print('📍 完整URL = $url'); - } - - KRLogUtil.kr_i('📤 请求网站配置 - $url', tag: 'KRSiteConfigService'); - if (kDebugMode) { - print('📤 准备发送 GET 请求到: $url'); - } - if (kDebugMode) { - // 🔧 修正日志,显示真实的超时配置 - print('⏱️ 超时配置: connectTimeout=${_dio.options.connectTimeout}, sendTimeout=${_dio.options.sendTimeout}, receiveTimeout=${_dio.options.receiveTimeout}'); - } - - if (kDebugMode) { - print('⏳ 开始发送请求...'); - } - final startTime = DateTime.now(); - final response = await _dio.get(url); - final endTime = DateTime.now(); - final duration = endTime.difference(startTime).inMilliseconds; - if (kDebugMode) { - print('⏱️ 请求耗时: ${duration}ms'); - } - - if (kDebugMode) { - print('✅ 请求完成,状态码: ${response.statusCode}'); - } - KRLogUtil.kr_i('📥 响应状态码 - ${response.statusCode}', tag: 'KRSiteConfigService'); - - if (response.statusCode == 200) { - final responseData = response.data; + while (retryCount < maxRetries) { + try { if (kDebugMode) { - print('📥 响应数据类型: ${responseData.runtimeType}'); + print('🔧 KRSiteConfigService.initialize() 开始执行 (尝试 ${retryCount + 1}/$maxRetries)'); + } + KRLogUtil.kr_i('🔧 开始初始化网站配置 (尝试 ${retryCount + 1}/$maxRetries)', tag: 'KRSiteConfigService'); + + // Debug 模式下使用固定地址 + final baseUrl = AppConfig().baseUrl; + if (kDebugMode) { + print('📍 baseUrl = $baseUrl'); + } + final url = '$baseUrl/v1/common/site/config'; + if (kDebugMode) { + print('📍 完整URL = $url'); + } + + KRLogUtil.kr_i('📤 请求网站配置 - $url', tag: 'KRSiteConfigService'); + if (kDebugMode) { + print('📤 准备发送 GET 请求到: $url'); } if (kDebugMode) { - print('📥 响应数据: $responseData'); + // 🔧 修正日志,显示真实的超时配置 + print('⏱️ 超时配置: connectTimeout=${_dio.options.connectTimeout}, sendTimeout=${_dio.options.sendTimeout}, receiveTimeout=${_dio.options.receiveTimeout}'); } - KRLogUtil.kr_i('📥 响应数据 - $responseData', tag: 'KRSiteConfigService'); - if (responseData['code'] == 200) { - _siteConfig = KRSiteConfig.fromJson(responseData['data']); - _isInitialized = true; + if (kDebugMode) { + print('⏳ 开始发送请求...'); + } + final startTime = DateTime.now(); + final response = await _dio.get(url); + final endTime = DateTime.now(); + final duration = endTime.difference(startTime).inMilliseconds; + if (kDebugMode) { + print('⏱️ 请求耗时: ${duration}ms'); + } - final config = AppConfig.getInstance(); - config.kr_website_id = getCrispId(); - config.device_limit = getDeviceLimit(); - // 打印配置信息 - _printConfigInfo(); + if (kDebugMode) { + print('✅ 请求完成,状态码: ${response.statusCode}'); + } + KRLogUtil.kr_i('📥 响应状态码 - ${response.statusCode}', tag: 'KRSiteConfigService'); - // 通知监听者配置已更新 - notifyListeners(); + if (response.statusCode == 200) { + final responseData = response.data; + if (kDebugMode) { + print('📥 响应数据类型: ${responseData.runtimeType}'); + } + if (kDebugMode) { + print('📥 响应数据: $responseData'); + } + KRLogUtil.kr_i('📥 响应数据 - $responseData', tag: 'KRSiteConfigService'); - return true; + if (responseData['code'] == 200) { + _siteConfig = KRSiteConfig.fromJson(responseData['data']); + _isInitialized = true; + + final config = AppConfig.getInstance(); + config.kr_website_id = getCrispId(); + config.device_limit = getDeviceLimit(); + // 打印配置信息 + _printConfigInfo(); + + // 通知监听者配置已更新 + notifyListeners(); + + return true; + } else { + KRLogUtil.kr_e('❌ API返回错误 - ${responseData['msg']}', tag: 'KRSiteConfigService'); + // API 返回业务错误,一般不重试,除非是特定错误码 + return false; + } } else { - KRLogUtil.kr_e('❌ API返回错误 - ${responseData['msg']}', tag: 'KRSiteConfigService'); - return false; + KRLogUtil.kr_e('❌ HTTP错误 - ${response.statusCode}', tag: 'KRSiteConfigService'); + // HTTP 错误(如 404, 500)通常也意味着该域名有问题,尝试切换 + // 但这里为了稳妥,先只针对网络异常重试,如果需要也可以改为抛出异常进入 catch + throw DioException( + requestOptions: response.requestOptions, + response: response, + type: DioExceptionType.badResponse, + error: 'HTTP Error ${response.statusCode}', + ); } - } else { - KRLogUtil.kr_e('❌ HTTP错误 - ${response.statusCode}', tag: 'KRSiteConfigService'); + } on DioException catch (e, stackTrace) { + if (kDebugMode) { + print('❌ Dio请求异常: ${e.type}'); + } + KRLogUtil.kr_e('❌ Dio异常 - ${e.type}: ${e.message}', tag: 'KRSiteConfigService'); + + // 检查是否是可以重试的错误类型 + if (e.type == DioExceptionType.connectionTimeout || + e.type == DioExceptionType.receiveTimeout || + e.type == DioExceptionType.sendTimeout || + e.type == DioExceptionType.connectionError || + e.type == DioExceptionType.unknown || // unknown 有时也是网络问题 + e.type == DioExceptionType.badResponse) { // 503 等服务器错误也值得重试 + + KRLogUtil.kr_w('⚠️ 网络或服务器异常,尝试切换域名重试...', tag: 'KRSiteConfigService'); + + // 尝试切换到下一个域名 + final switchSuccess = await KRDomain.kr_switchToNextDomain(); + if (switchSuccess) { + retryCount++; + KRLogUtil.kr_i('✅ 域名切换成功,准备第 ${retryCount + 1} 次尝试', tag: 'KRSiteConfigService'); + continue; // 重新进入循环 + } else { + KRLogUtil.kr_e('❌ 域名切换失败,无法继续重试', tag: 'KRSiteConfigService'); + return false; + } + } + + // 如果是不可重试的错误,直接返回失败 + KRLogUtil.kr_e('📚 堆栈: $stackTrace', tag: 'KRSiteConfigService'); + return false; + } catch (e, stackTrace) { + if (kDebugMode) { + print('❌ 未知异常: $e'); + } + KRLogUtil.kr_e('❌ 初始化失败 - $e', tag: 'KRSiteConfigService'); + KRLogUtil.kr_e('📚 堆栈: $stackTrace', tag: 'KRSiteConfigService'); return false; } - } on DioException catch (e, stackTrace) { - if (kDebugMode) { - print('❌ Dio请求异常: ${e.type}'); - } - if (kDebugMode) { - print('❌ 错误信息: ${e.message}'); - } - if (kDebugMode) { - print('❌ 请求URL: ${e.requestOptions.uri}'); - } - if (kDebugMode) { - print('❌ 连接超时: ${e.requestOptions.connectTimeout}'); - } - if (kDebugMode) { - print('❌ 发送超时: ${e.requestOptions.sendTimeout}'); - } - if (kDebugMode) { - print('❌ 接收超时: ${e.requestOptions.receiveTimeout}'); - } - if (e.response != null) { - if (kDebugMode) { - print('❌ 响应状态码: ${e.response?.statusCode}'); - } - if (kDebugMode) { - print('❌ 响应数据: ${e.response?.data}'); - } - } - if (kDebugMode) { - print('📚 堆栈跟踪: $stackTrace'); - } - - KRLogUtil.kr_e('❌ Dio异常 - ${e.type}: ${e.message}', tag: 'KRSiteConfigService'); - KRLogUtil.kr_e('📚 堆栈: $stackTrace', tag: 'KRSiteConfigService'); - return false; - } catch (e, stackTrace) { - if (kDebugMode) { - print('❌ 未知异常: $e'); - } - if (kDebugMode) { - print('📚 堆栈跟踪: $stackTrace'); - } - KRLogUtil.kr_e('❌ 初始化失败 - $e', tag: 'KRSiteConfigService'); - KRLogUtil.kr_e('📚 堆栈: $stackTrace', tag: 'KRSiteConfigService'); - return false; } + + KRLogUtil.kr_e('❌ 达到最大重试次数 ($maxRetries),初始化失败', tag: 'KRSiteConfigService'); + return false; } /// 打印配置信息 diff --git a/lib/app/services/singbox_imp/kr_sing_box_imp.dart b/lib/app/services/singbox_imp/kr_sing_box_imp.dart index 8da42a8..3817b50 100755 --- a/lib/app/services/singbox_imp/kr_sing_box_imp.dart +++ b/lib/app/services/singbox_imp/kr_sing_box_imp.dart @@ -689,6 +689,23 @@ class KRSingBoxImp { List> _kr_buildHiddifyRules() { final rules = >[]; rules.add({"domains": "domain:api.hifast.biz", "outbound": "bypass"}); + // 使用 domain:crisp.chat (这通常会匹配所有子域名) + rules.add({"domains": "domain:crisp.chat", "outbound": "bypass"}); + // 某些 sing-box 版本可能需要显式包含 relay 域名 + rules.add({"domains": "domain:client.relay.crisp.chat", "outbound": "bypass"}); + + // 🔧 新增:将动态域名列表加入到规则中 (直连) + // 使用 Set 去重,避免重复添加 + final baseDomains = KRDomain.kr_baseDomains.toSet(); + KRLogUtil.kr_i('🔄 将 ${baseDomains.length} 个动态域名加入直连规则: $baseDomains', tag: 'SingBox'); + + for (final domain in baseDomains) { + if (domain.isNotEmpty) { + // 检查是否已经存在(虽然Set去重了,但上面的硬编码可能重复) + // 简单起见直接添加,sing-box 通常能处理重复规则,或者规则越前优先级越高 + rules.add({"domains": "domain:$domain", "outbound": "bypass"}); + } + } final nodeDomains = _kr_collectNodeDomains(); for (final d in nodeDomains) { diff --git a/lib/app/widgets/hi_collapsible_list.dart b/lib/app/widgets/hi_collapsible_list.dart index 496567e..d4e87e6 100644 --- a/lib/app/widgets/hi_collapsible_list.dart +++ b/lib/app/widgets/hi_collapsible_list.dart @@ -60,6 +60,7 @@ class _HICollapsibleItemWidgetState extends State { text: linkText, style: const TextStyle( color: const Color(0xFFADFF5B), // 链接颜色 + fontFamily: 'AlibabaPuHuiTi-Regular', ), recognizer: TapGestureRecognizer() ..onTap = () async {