import 'dart:async'; import 'package:get/get.dart'; import 'package:kaer_with_panels/app/model/response/kr_node_group_list.dart'; import 'package:kaer_with_panels/app/model/response/kr_user_available_subscribe.dart'; import 'package:kaer_with_panels/app/services/api_service/kr_subscribe_api.dart'; import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart'; import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; import 'package:kaer_with_panels/app/utils/kr_common_util.dart'; import 'package:kaer_with_panels/app/localization/app_translations.dart'; import '../../singbox/model/singbox_status.dart'; import '../model/business/kr_group_outbound_list.dart'; import '../model/business/kr_outbound_item.dart'; import '../model/business/kr_outbounds_list.dart'; import '../model/response/kr_already_subscribe.dart'; /// 首页列表视图状态枚举 enum KRSubscribeServiceStatus { kr_none, kr_loading, kr_error, kr_success } /// 订阅服务类 /// 用于管理用户订阅相关的所有操作 class KRSubscribeService { /// 单例实例 static final KRSubscribeService _instance = KRSubscribeService._internal(); /// 工厂构造函数 factory KRSubscribeService() => _instance; /// 私有构造函数 KRSubscribeService._internal() {} /// 订阅API final KRSubscribeApi kr_subscribeApi = KRSubscribeApi(); /// 可用订阅列表 final RxList kr_availableSubscribes = [].obs; /// 当前选中的订阅 final Rx kr_currentSubscribe = Rx(null); /// 节点分组列表 final RxList kr_nodeGroups = [].obs; /// 服务器分组 final RxList groupOutboundList = [].obs; /// 国家分组,包含所有国家 final RxList countryOutboundList = [].obs; /// 全部列表 final RxList allList = [].obs; /// 标签列表 Map keyList = {}; // 存储国家分组的列表 /// 试用剩余时间 final RxString kr_trialRemainingTime = ''.obs; /// 订阅剩余时间 final RxString kr_subscriptionRemainingTime = ''.obs; /// 剩余时间 final RxString remainingTime = ''.obs; /// 是否处于试用状态 final RxBool kr_isTrial = false.obs; /// 订阅记录 final RxList kr_alreadySubscribe = [].obs; /// 是否处于订阅最后一天 final RxBool kr_isLastDayOfSubscription = false.obs; /// 定期更新计时器 Timer? _kr_updateTimer; /// 试用倒计时计时器 Timer? _kr_trialTimer; /// 订阅倒计时计时器 Timer? _kr_subscriptionTimer; /// 当前状态 final kr_currentStatus = KRSubscribeServiceStatus.kr_none.obs; /// 重置订阅周期 Future kr_resetSubscribePeriod() async { if (kr_currentSubscribe.value == null) { KRCommonUtil.kr_showToast('请先选择订阅'); return; } final result = await kr_subscribeApi .kr_resetSubscribePeriod(kr_currentSubscribe.value!.id); result.fold( (error) { KRCommonUtil.kr_showToast(error.msg); KRLogUtil.kr_e('重置订阅周期失败: ${error.msg}', tag: 'SubscribeService'); }, (success) { kr_refreshAll(); KRLogUtil.kr_i('重置订阅周期成功', tag: 'SubscribeService'); }, ); } /// 获取可用订阅列表 Future _kr_fetchAvailableSubscribes() async { try { KRLogUtil.kr_i('开始获取可用订阅列表', tag: 'SubscribeService'); final result = await kr_subscribeApi.kr_userAvailableSubscribe(); result.fold( (error) { KRLogUtil.kr_e('获取可用订阅失败: ${error.msg}', tag: 'SubscribeService'); }, (subscribes) { // 如果当前有选中的订阅,检查是否还在可用列表中 if (kr_currentSubscribe.value != null) { final currentSubscribeExists = subscribes.any( (subscribe) => subscribe.id == kr_currentSubscribe.value?.id, ); // 如果当前订阅不在可用列表中,清除当前订阅 if (!currentSubscribeExists) { // 如果当前订阅为null或者已过期,才设置新的订阅 if (kr_currentSubscribe.value == null || DateTime.parse(kr_currentSubscribe.value!.expireTime) .isBefore(DateTime.now())) { kr_availableSubscribes.assignAll(subscribes); if (subscribes.isNotEmpty) { kr_currentSubscribe.value = subscribes.first; KRLogUtil.kr_i('设置新的订阅: ${subscribes.first.name}', tag: 'SubscribeService'); } else { kr_currentSubscribe.value = null; KRLogUtil.kr_i('没有可用的订阅,清除选中状态', tag: 'SubscribeService'); } kr_clearCutNodeData(); } else { KRLogUtil.kr_i('当前订阅仍然有效,保持选中状态', tag: 'SubscribeService'); } } else { // 如果当前订阅仍然有效,更新为最新的订阅信息 final updatedSubscribe = subscribes.firstWhere( (subscribe) => subscribe.id == kr_currentSubscribe.value?.id, ); // 检查订阅是否有效(未过期且未超出流量限制) final isExpired = DateTime.parse(updatedSubscribe.expireTime) .isBefore(DateTime.now()); final isOverTraffic = updatedSubscribe.traffic > 0 && (updatedSubscribe.download + updatedSubscribe.upload) >= updatedSubscribe.traffic; if (isExpired || isOverTraffic) { if (KRSingBoxImp.instance.kr_status == SingboxStatus.started()) { KRSingBoxImp.instance.kr_stop(); } } kr_currentSubscribe.value = updatedSubscribe; KRLogUtil.kr_i('更新当前订阅信息', tag: 'SubscribeService'); // 更新可用订阅列表 kr_availableSubscribes.assignAll(subscribes); } } KRLogUtil.kr_i('获取可用订阅列表成功: ${subscribes.length} 个订阅', tag: 'SubscribeService'); KRLogUtil.kr_i( '订阅列表: ${subscribes.map((s) => '${s.name}(${s.id})').join(', ')}', tag: 'SubscribeService'); }, ); } catch (err) { KRLogUtil.kr_e('获取可用订阅异常: $err', tag: 'SubscribeService'); } } /// 切换订阅 Future kr_switchSubscribe( KRUserAvailableSubscribeItem subscribe) async { // 如果切换的是当前订阅,直接返回 if (subscribe.id == kr_currentSubscribe.value?.id) { KRLogUtil.kr_i('切换的订阅与当前订阅相同,无需切换', tag: 'SubscribeService'); return; } try { kr_currentStatus.value = KRSubscribeServiceStatus.kr_loading; await kr_clearCutNodeData(); KRLogUtil.kr_i('开始切换订阅: ${subscribe.name + subscribe.id.toString()}', tag: 'SubscribeService'); // 更新当前订阅 kr_currentSubscribe.value = subscribe; final result = await kr_subscribeApi.kr_nodeList(kr_currentSubscribe.value!.id); result.fold((error) { kr_currentStatus.value = KRSubscribeServiceStatus.kr_error; }, (nodes) { // 处理节点列表 final listModel = KrOutboundsList(); listModel.processOutboundItems(nodes.list, kr_nodeGroups); // 更新UI数据 groupOutboundList.value = listModel.groupOutboundList; countryOutboundList.value = listModel.countryOutboundList; allList.value = listModel.allList; keyList = listModel.keyList; // 保存配置 KRSingBoxImp.instance.kr_saveOutbounds(listModel.configJsonList); // 更新试用和订阅状态 _kr_updateSubscribeStatus(); kr_currentStatus.value = KRSubscribeServiceStatus.kr_success; }); } catch (e) { kr_currentStatus.value = KRSubscribeServiceStatus.kr_error; KRLogUtil.kr_e('切换订阅失败: $e', tag: 'SubscribeService'); rethrow; } } /// 更新订阅状态 void _kr_updateSubscribeStatus() { // 停止之前的计时器 _kr_trialTimer?.cancel(); _kr_subscriptionTimer?.cancel(); // 检查试用状态 final bool kr_isSubscribed = kr_currentSubscribe.value != null && kr_alreadySubscribe.any((subscribe) => kr_currentSubscribe.value?.id == subscribe.userSubscribeId); KRLogUtil.kr_i('当前订阅状态: ${kr_isSubscribed ? "已订阅" : "未订阅"}', tag: 'SubscribeService'); KRLogUtil.kr_i('当前订阅ID: ${kr_currentSubscribe.value?.id}', tag: 'SubscribeService'); KRLogUtil.kr_i( '已订阅记录: ${kr_alreadySubscribe.map((s) => s.userSubscribeId).join(', ')}', tag: 'SubscribeService'); // 设置试用状态 kr_isTrial.value = kr_currentSubscribe.value != null && !kr_isSubscribed; KRLogUtil.kr_i('试用状态: ${kr_isTrial.value ? "是" : "否"}', tag: 'SubscribeService'); if (kr_isTrial.value) { // 启动试用倒计时 _kr_startTrialTimer(); } // 检查订阅状态 else if (kr_currentSubscribe.value != null) { final expireTime = DateTime.parse(kr_currentSubscribe.value!.expireTime); final now = DateTime.now(); final difference = expireTime.difference(now); // 检查是否最后一天 kr_isLastDayOfSubscription.value = difference.inDays <= 1; if (kr_isLastDayOfSubscription.value) { // 启动订阅倒计时 _kr_startSubscriptionTimer(); KRLogUtil.kr_i('当前订阅最后一天', tag: 'SubscribeService'); } } } /// 启动试用倒计时 void _kr_startTrialTimer() { _kr_trialTimer?.cancel(); // 立即执行一次 _kr_updateTrialTime(); // 设置定时器 _kr_trialTimer = Timer.periodic(const Duration(seconds: 1), (timer) { _kr_updateTrialTime(); }); } /// 更新试用时间 void _kr_updateTrialTime() { if (kr_currentSubscribe.value == null) { _kr_trialTimer?.cancel(); return; } final expireTime = DateTime.parse(kr_currentSubscribe.value!.expireTime); final now = DateTime.now(); final difference = expireTime.difference(now); if (difference.isNegative) { /// 停止 if (KRSingBoxImp.instance.kr_status == SingboxStatus.started()) { KRSingBoxImp.instance.kr_stop(); } _kr_trialTimer?.cancel(); kr_trialRemainingTime.value = 'error.60001'.tr; return; } final days = difference.inDays; final hours = difference.inHours % 24; final minutes = difference.inMinutes % 60; final seconds = difference.inSeconds % 60; kr_trialRemainingTime.value = AppTranslations.kr_home.trialTimeWithDays( days, hours, minutes, seconds, ); } /// 启动订阅倒计时 void _kr_startSubscriptionTimer() { _kr_subscriptionTimer?.cancel(); // 立即执行一次 _kr_updateSubscriptionTime(); // 设置定时器 _kr_subscriptionTimer = Timer.periodic(const Duration(seconds: 1), (timer) { _kr_updateSubscriptionTime(); }); } /// 更新订阅时间 void _kr_updateSubscriptionTime() { if (kr_currentSubscribe.value == null) { _kr_subscriptionTimer?.cancel(); return; } final expireTime = DateTime.parse(kr_currentSubscribe.value!.expireTime); final now = DateTime.now(); final difference = expireTime.difference(now); if (difference.isNegative) { _kr_subscriptionTimer?.cancel(); /// 停止 if (KRSingBoxImp.instance.kr_status == SingboxStatus.started()) { KRSingBoxImp.instance.kr_stop(); } kr_subscriptionRemainingTime.value = 'error.60001'.tr; ; return; } final days = difference.inDays; final hours = difference.inHours % 24; final minutes = difference.inMinutes % 60; final seconds = difference.inSeconds % 60; kr_subscriptionRemainingTime.value = AppTranslations.kr_home.trialTimeWithDays( days, hours, minutes, seconds, ); } /// 启动定期更新 void _kr_startPeriodicUpdate() { // 每5分钟更新一次可用订阅列表 _kr_updateTimer = Timer.periodic(const Duration(seconds: 60), (timer) { _kr_fetchAvailableSubscribes(); }); } /// 刷新所有数据 Future kr_refreshAll() async { try { kr_currentStatus.value = KRSubscribeServiceStatus.kr_loading; await kr_clearData(); KRLogUtil.kr_i('开始刷新所有数据', tag: 'SubscribeService'); /// 数组有值 ,表示订阅过, 用于判断试用的 final alreadySubscribeResult = await kr_subscribeApi.kr_getAlreadySubscribe(); alreadySubscribeResult.fold( (error) { throw Exception('获取已订阅列表失败: ${error.msg}'); }, (subscribes) { kr_alreadySubscribe.value = subscribes; KRLogUtil.kr_i('订阅记录: ${subscribes.length} 个订阅', tag: 'SubscribeService'); }, ); final result = await kr_subscribeApi.kr_nodeGroupList(); result.fold( (error) { throw Exception('获取节点分组失败: ${error.msg}'); }, (groups) { kr_nodeGroups.value = groups; }, ); // 保存当前选中的订阅名称 final currentSubscribeID = kr_currentSubscribe.value?.id; // 获取可用订阅列表 final subscribeResult = await kr_subscribeApi.kr_userAvailableSubscribe(); // 处理订阅列表结果 final subscribes = await subscribeResult.fold( (error) { throw Exception('获取可用订阅失败: ${error.msg}'); }, (subscribes) => subscribes, ); // 如果获取订阅列表失败,直接返回 if (subscribes.isEmpty) { kr_currentStatus.value = KRSubscribeServiceStatus.kr_none; kr_availableSubscribes.clear(); return; } // 更新订阅列表 kr_availableSubscribes.assignAll(subscribes); KRLogUtil.kr_i('获取可用订阅列表成功: ${subscribes.length} 个订阅', tag: 'SubscribeService'); // 如果之前的订阅名称在可用列表中,保持选中 if (subscribes.isNotEmpty) { final previousSubscribe = subscribes.firstWhere( (subscribe) => subscribe.id == currentSubscribeID, orElse: () => subscribes.first, ); if (previousSubscribe.id != currentSubscribeID) { kr_currentSubscribe.value = previousSubscribe; KRLogUtil.kr_i('切换订阅: ${previousSubscribe.name}', tag: 'SubscribeService'); } else { kr_currentSubscribe.value = previousSubscribe; } // 获取节点列表 final nodeResult = await kr_subscribeApi.kr_nodeList(kr_currentSubscribe.value!.id); // 处理节点列表结果 final nodes = await nodeResult.fold( (error) { throw Exception('获取节点列表失败: ${error.msg}'); }, (nodes) => nodes, ); // 处理节点列表 final listModel = KrOutboundsList(); listModel.processOutboundItems(nodes.list, kr_nodeGroups); // 更新UI数据 groupOutboundList.value = listModel.groupOutboundList; countryOutboundList.value = listModel.countryOutboundList; allList.value = listModel.allList; keyList = listModel.keyList; // 保存配置 KRSingBoxImp.instance.kr_saveOutbounds(listModel.configJsonList); // 更新试用和订阅状态 _kr_updateSubscribeStatus(); kr_currentStatus.value = KRSubscribeServiceStatus.kr_success; _kr_startPeriodicUpdate(); } else { KRLogUtil.kr_w('没有可用的订阅', tag: 'SubscribeService'); kr_currentStatus.value = KRSubscribeServiceStatus.kr_error; return; } } catch (err, stackTrace) { kr_currentStatus.value = KRSubscribeServiceStatus.kr_error; KRLogUtil.kr_e('刷新数据异常: $err\n$stackTrace', tag: 'SubscribeService'); } } //// 清楚 Future kr_clearData() async { _kr_subscriptionTimer?.cancel(); _kr_trialTimer?.cancel(); _kr_updateTimer?.cancel(); kr_availableSubscribes.clear(); await kr_clearCutNodeData(); } Future kr_logout() async { kr_alreadySubscribe.clear(); kr_nodeGroups.clear(); kr_currentSubscribe.value = null; await kr_clearData(); } Future kr_clearCutNodeData() async { kr_isLastDayOfSubscription.value = false; kr_isTrial.value = false; kr_subscriptionRemainingTime.value = ''; kr_trialRemainingTime.value = ''; /// 停止 if (KRSingBoxImp.instance.kr_status == SingboxStatus.started()) { await KRSingBoxImp.instance.kr_stop(); } // 更新UI数据 groupOutboundList.clear(); countryOutboundList.clear(); allList.clear(); keyList.clear(); // 保存配置 KRSingBoxImp.instance.kr_saveOutbounds([]); } /// 获取当前订阅 KRUserAvailableSubscribeItem? get kr_getCurrentSubscribe => kr_currentSubscribe.value; }