import json import webbrowser from PySide6.QtWidgets import QMessageBox from utils import load_config, save_config, msgbox_frame class ConfigManager: """配置管理器,用于处理配置的加载、保存和获取云端配置""" def __init__(self, app_name, config_url, ua, debug_manager=None): """初始化配置管理器 Args: app_name: 应用程序名称,用于显示消息框标题 config_url: 云端配置URL ua: User-Agent字符串 debug_manager: 调试管理器实例,用于输出调试信息 """ self.app_name = app_name self.config_url = config_url self.ua = ua self.debug_manager = debug_manager self.cloud_config = None self.config_valid = False self.last_error_message = "" def _is_debug_mode(self): """检查是否处于调试模式 Returns: bool: 是否处于调试模式 """ if hasattr(self.debug_manager, 'ui_manager') and hasattr(self.debug_manager.ui_manager, 'debug_action'): return self.debug_manager.ui_manager.debug_action.isChecked() return False def load_config(self): """加载本地配置 Returns: dict: 加载的配置 """ return load_config() def save_config(self, config): """保存配置 Args: config: 要保存的配置 """ save_config(config) def fetch_cloud_config(self, config_fetch_thread_class, callback=None): """获取云端配置 Args: config_fetch_thread_class: 用于获取云端配置的线程类 callback: 获取完成后的回调函数,接受两个参数(data, error_message) """ headers = {"User-Agent": self.ua} debug_mode = self._is_debug_mode() self.config_fetch_thread = config_fetch_thread_class(self.config_url, headers, debug_mode) # 如果提供了回调,使用它;否则使用内部的on_config_fetched方法 if callback: self.config_fetch_thread.finished.connect(callback) else: self.config_fetch_thread.finished.connect(self.on_config_fetched) self.config_fetch_thread.start() def on_config_fetched(self, data, error_message): """云端配置获取完成的回调处理 Args: data: 获取到的配置数据 error_message: 错误信息,如果有 """ debug_mode = self._is_debug_mode() if error_message: # 标记配置无效 self.config_valid = False # 记录错误信息,用于按钮点击时显示 if error_message == "update_required": self.last_error_message = "update_required" # 检查是否处于离线模式 is_offline_mode = False if hasattr(self.debug_manager, 'main_window') and hasattr(self.debug_manager.main_window, 'offline_mode_manager'): is_offline_mode = self.debug_manager.main_window.offline_mode_manager.is_in_offline_mode() if is_offline_mode: # 离线模式下只显示提示,不禁用开始安装按钮 msg_box = msgbox_frame( f"更新提示 - {self.app_name}", "\n当前版本过低,请及时更新。\n在离线模式下,您仍可使用禁用/启用补丁、卸载补丁和离线安装功能。\n", QMessageBox.StandardButton.Ok, ) msg_box.exec() # 移除在浏览器中打开项目主页的代码 # 离线模式下版本过低,仍然允许使用安装按钮 return {"action": "enable_button"} else: # 在线模式下显示强制更新提示 msg_box = msgbox_frame( f"更新提示 - {self.app_name}", "\n当前版本过低,请及时更新。\n如需联网下载补丁,请更新到最新版,否则无法下载。\n", QMessageBox.StandardButton.Ok, ) msg_box.exec() # 移除在浏览器中打开项目主页的代码 # 在线模式下版本过低,但不直接禁用按钮,而是在点击时提示 return {"action": "enable_button", "version_warning": True} elif "missing_keys" in error_message: self.last_error_message = "missing_keys" missing_versions = error_message.split(":")[1] msg_box = msgbox_frame( f"配置缺失 - {self.app_name}", f'\n云端缺失下载链接,可能云服务器正在维护,不影响其他版本下载。\n当前缺失版本:"{missing_versions}"\n', QMessageBox.StandardButton.Ok, ) msg_box.exec() # 对于部分缺失,仍然允许使用,因为可能只影响部分游戏版本 self.config_valid = True return {"action": "enable_button"} else: # 设置网络错误标记 self.last_error_message = "network_error" # 显示通用错误消息,只在debug模式下显示详细错误 error_msg = "访问云端配置失败,请检查网络状况或稍后再试。" if debug_mode and "详细错误:" in error_message: msg_box = msgbox_frame( f"错误 - {self.app_name}", f"\n{error_message}\n", QMessageBox.StandardButton.Ok, ) else: msg_box = msgbox_frame( f"错误 - {self.app_name}", f"\n{error_msg}\n", QMessageBox.StandardButton.Ok, ) msg_box.exec() # 网络错误时仍然允许使用按钮,用户可以尝试离线模式 return {"action": "enable_button"} else: self.cloud_config = data # 标记配置有效 self.config_valid = True # 清除错误信息 self.last_error_message = "" if debug_mode: print("--- Cloud config fetched successfully ---") # 创建一个数据副本,隐藏敏感URL safe_data = self._create_safe_config_for_logging(data) print(json.dumps(safe_data, indent=2)) # 获取配置成功,允许安装 return {"action": "enable_button"} def _create_safe_config_for_logging(self, config_data): """创建用于日志记录的安全配置副本,隐藏敏感URL Args: config_data: 原始配置数据 Returns: dict: 安全的配置数据副本 """ if not config_data or not isinstance(config_data, dict): return config_data # 创建深拷贝,避免修改原始数据 import copy safe_config = copy.deepcopy(config_data) # 隐藏敏感URL for key in safe_config: if isinstance(safe_config[key], dict) and "url" in safe_config[key]: # 完全隐藏URL safe_config[key]["url"] = "***URL protection***" return safe_config def is_config_valid(self): """检查配置是否有效 Returns: bool: 配置是否有效 """ return self.config_valid def get_cloud_config(self): """获取云端配置 Returns: dict: 云端配置 """ return self.cloud_config def get_last_error(self): """获取最后一次错误信息 Returns: str: 错误信息 """ return self.last_error_message