import json import os import subprocess import requests from typing import Dict, Optional, Tuple from ..utils.crypto import encrypt, decrypt class ConfigManager: """配置文件管理器""" def __init__(self, storage_path: str = "ab", cdn_base_url: str = ""): self.storage_path = storage_path self.cdn_base_url = cdn_base_url def version_to_path(self, version: str) -> str: """将版本号转换为存储路径格式""" # 0.29 -> 0_29 return version.replace('.', '_') def get_config_path(self, version: str, platform: str) -> str: """获取配置文件在对象存储中的路径""" version_path = self.version_to_path(version) filename = f"{platform}config.json" return f"{self.storage_path}/{version_path}/{filename}" def get_cdn_url(self, version: str, platform: str) -> str: """获取配置文件在CDN中的URL""" if not self.cdn_base_url: return "" version_path = self.version_to_path(version) filename = f"{platform}config.json" return f"{self.cdn_base_url}/{self.storage_path}/{version_path}/{filename}" def download_from_storage(self, version: str, platform: str) -> Optional[str]: """从对象存储下载并解密配置文件""" try: config_path = self.get_config_path(version, platform) # 使用rclone下载文件 result = subprocess.run( ["rclone", "cat", config_path], capture_output=True, text=True, timeout=30 ) if result.returncode != 0: print(f"警告: 无法从对象存储下载 {config_path}: {result.stderr}") return None # 解密文件内容 encrypted_content = result.stdout.strip() if not encrypted_content: print(f"警告: 文件 {config_path} 为空") return None decrypted_content = decrypt(encrypted_content) return decrypted_content except subprocess.TimeoutExpired: print(f"错误: 下载 {config_path} 超时") return None except Exception as e: print(f"错误: 下载 {config_path} 失败: {str(e)}") return None def get_from_cdn(self, version: str, platform: str) -> Optional[str]: """从CDN获取配置文件内容""" try: cdn_url = self.get_cdn_url(version, platform) if not cdn_url: print(f"警告: CDN URL未配置,跳过CDN内容获取") return None response = requests.get(cdn_url, timeout=10) response.raise_for_status() # CDN中的内容应该是解密后的JSON return response.text except requests.RequestException as e: print(f"警告: 无法从CDN获取 {cdn_url}: {str(e)}") return None except Exception as e: print(f"错误: 获取CDN内容失败: {str(e)}") return None def parse_config(self, content: str) -> Optional[Dict]: """解析配置文件内容""" try: return json.loads(content) except json.JSONDecodeError as e: print(f"错误: 配置文件格式错误: {str(e)}") return None def compare_configs(self, storage_config: Dict, cdn_config: Dict) -> Dict: """比较存储配置和CDN配置的差异""" all_keys = set(storage_config.keys()) | set(cdn_config.keys()) differences = {} for key in sorted(all_keys): storage_value = storage_config.get(key, "N/A") cdn_value = cdn_config.get(key, "N/A") if storage_value != cdn_value: differences[key] = { "storage": storage_value, "cdn": cdn_value, "different": True } else: differences[key] = { "storage": storage_value, "cdn": cdn_value, "different": False } return differences