|
| 1 | +# ================================================== |
| 2 | +# 导入模块 |
| 3 | +# ================================================== |
| 4 | +import yaml |
| 5 | +import aiohttp |
| 6 | +from loguru import logger |
| 7 | +from app.tools.path_utils import * |
| 8 | +from app.tools.settings_access import readme_settings |
| 9 | + |
| 10 | +# ================================================== |
| 11 | +# 更新工具函数 |
| 12 | +# ================================================== |
| 13 | + |
| 14 | + |
| 15 | +async def get_metadata_info_async(): |
| 16 | + """ |
| 17 | + 异步获取 metadata.yaml 文件信息 |
| 18 | +
|
| 19 | + Returns: |
| 20 | + dict: metadata.yaml 文件的内容,如果读取失败则返回 None |
| 21 | + """ |
| 22 | + try: |
| 23 | + # 获取更新检查 URL |
| 24 | + update_check_url = get_update_check_url() |
| 25 | + logger.debug(f"从网络获取 metadata.yaml: {update_check_url}") |
| 26 | + |
| 27 | + # 发送异步请求 |
| 28 | + async with aiohttp.ClientSession() as session: |
| 29 | + async with session.get(update_check_url, timeout=10) as response: |
| 30 | + response.raise_for_status() # 检查请求是否成功 |
| 31 | + content = await response.text() |
| 32 | + |
| 33 | + # 解析 YAML 内容 |
| 34 | + metadata = yaml.safe_load(content) |
| 35 | + logger.debug(f"成功从网络读取 metadata.yaml 文件: {metadata}") |
| 36 | + return metadata |
| 37 | + except Exception as e: |
| 38 | + logger.error(f"从网络获取 metadata.yaml 文件失败: {e}") |
| 39 | + return None |
| 40 | + |
| 41 | + |
| 42 | +def get_metadata_info(): |
| 43 | + """ |
| 44 | + 获取 metadata.yaml 文件信息(同步版本) |
| 45 | +
|
| 46 | + Returns: |
| 47 | + dict: metadata.yaml 文件的内容,如果读取失败则返回 None |
| 48 | + """ |
| 49 | + try: |
| 50 | + # 使用 asyncio 运行异步函数 |
| 51 | + import asyncio |
| 52 | + |
| 53 | + return asyncio.run(get_metadata_info_async()) |
| 54 | + except Exception as e: |
| 55 | + logger.error(f"同步获取 metadata.yaml 文件失败: {e}") |
| 56 | + return None |
| 57 | + |
| 58 | + |
| 59 | +async def get_latest_version_async(channel=None): |
| 60 | + """ |
| 61 | + 获取最新版本信息(异步版本) |
| 62 | +
|
| 63 | + Args: |
| 64 | + channel (str, optional): 更新通道,默认为 None,此时会从设置中读取 |
| 65 | + 0: 稳定通道(release), 1: 测试通道(beta), 2: 发布预览通道 |
| 66 | +
|
| 67 | + Returns: |
| 68 | + dict: 包含版本号和版本号数字的字典,格式为 {"version": str, "version_no": int} |
| 69 | + """ |
| 70 | + try: |
| 71 | + # 如果没有指定通道,从设置中读取 |
| 72 | + if channel is None: |
| 73 | + channel = readme_settings("update", "update_channel") |
| 74 | + |
| 75 | + # 获取 metadata 信息(异步) |
| 76 | + metadata = await get_metadata_info_async() |
| 77 | + if not metadata: |
| 78 | + return None |
| 79 | + |
| 80 | + # 根据通道获取对应的版本信息 |
| 81 | + channel_map = { |
| 82 | + 0: "release", # 稳定通道 |
| 83 | + 1: "beta", # 测试通道 |
| 84 | + 2: "alpha", # 发布预览通道 |
| 85 | + } |
| 86 | + |
| 87 | + channel_name = channel_map.get(channel, "release") |
| 88 | + latest = metadata.get("latest", {}) |
| 89 | + latest_no = metadata.get("latest_no", {}) |
| 90 | + |
| 91 | + version = latest.get(channel_name, "") |
| 92 | + version_no = latest_no.get(channel_name, 0) |
| 93 | + |
| 94 | + logger.debug( |
| 95 | + f"获取最新版本信息成功: 通道={channel_name}, 版本={version}, 版本号={version_no}" |
| 96 | + ) |
| 97 | + return {"version": version, "version_no": version_no} |
| 98 | + except Exception as e: |
| 99 | + logger.error(f"获取最新版本信息失败: {e}") |
| 100 | + return None |
| 101 | + |
| 102 | + |
| 103 | +def get_latest_version(channel=None): |
| 104 | + """ |
| 105 | + 获取最新版本信息(同步版本) |
| 106 | +
|
| 107 | + Args: |
| 108 | + channel (str, optional): 更新通道,默认为 None,此时会从设置中读取 |
| 109 | + 0: 稳定通道(release), 1: 测试通道(beta), 2: 发布预览通道 |
| 110 | +
|
| 111 | + Returns: |
| 112 | + dict: 包含版本号和版本号数字的字典,格式为 {"version": str, "version_no": int} |
| 113 | + """ |
| 114 | + try: |
| 115 | + # 使用 asyncio 运行异步函数 |
| 116 | + import asyncio |
| 117 | + |
| 118 | + return asyncio.run(get_latest_version_async(channel)) |
| 119 | + except Exception as e: |
| 120 | + logger.error(f"获取最新版本信息失败: {e}") |
| 121 | + return None |
| 122 | + |
| 123 | + |
| 124 | +def get_update_source_url(): |
| 125 | + """ |
| 126 | + 获取更新源 URL |
| 127 | +
|
| 128 | + Returns: |
| 129 | + str: 更新源 URL,如果获取失败则返回默认值 |
| 130 | + """ |
| 131 | + try: |
| 132 | + # 从设置中读取更新源 |
| 133 | + update_source = readme_settings("update", "update_source") |
| 134 | + |
| 135 | + # 更新源映射 |
| 136 | + source_map = { |
| 137 | + 0: "https://github.com", # GitHub |
| 138 | + 1: "https://ghfast.top", # ghfast |
| 139 | + 2: "https://gh-proxy.com", # gh-proxy |
| 140 | + } |
| 141 | + |
| 142 | + source_url = source_map.get(update_source, "https://github.com") |
| 143 | + logger.debug(f"获取更新源 URL 成功: {source_url}") |
| 144 | + return source_url |
| 145 | + except Exception as e: |
| 146 | + logger.error(f"获取更新源 URL 失败: {e}") |
| 147 | + return "https://github.com" |
| 148 | + |
| 149 | + |
| 150 | +def compare_versions(current_version, latest_version): |
| 151 | + """ |
| 152 | + 比较版本号 |
| 153 | +
|
| 154 | + Args: |
| 155 | + current_version (str): 当前版本号,格式为 "vX.X.X.X" |
| 156 | + latest_version (str): 最新版本号,格式为 "vX.X.X.X" |
| 157 | +
|
| 158 | + Returns: |
| 159 | + int: 1 表示有新版本,0 表示版本相同,-1 表示比较失败 |
| 160 | + """ |
| 161 | + try: |
| 162 | + # 移除版本号前缀 "v" |
| 163 | + current = current_version.lstrip("v") |
| 164 | + latest = latest_version.lstrip("v") |
| 165 | + |
| 166 | + # 分割版本号为列表 |
| 167 | + current_parts = list(map(int, current.split("."))) |
| 168 | + latest_parts = list(map(int, latest.split("."))) |
| 169 | + |
| 170 | + # 比较版本号 |
| 171 | + for i in range(max(len(current_parts), len(latest_parts))): |
| 172 | + current_part = current_parts[i] if i < len(current_parts) else 0 |
| 173 | + latest_part = latest_parts[i] if i < len(latest_parts) else 0 |
| 174 | + |
| 175 | + if latest_part > current_part: |
| 176 | + return 1 |
| 177 | + elif latest_part < current_part: |
| 178 | + return -1 |
| 179 | + |
| 180 | + return 0 |
| 181 | + except Exception as e: |
| 182 | + logger.error(f"比较版本号失败: {e}") |
| 183 | + return -1 |
| 184 | + |
| 185 | + |
| 186 | +async def get_update_file_name_async(version, arch="x64", struct="dir"): |
| 187 | + """ |
| 188 | + 获取更新文件名(异步版本) |
| 189 | +
|
| 190 | + Args: |
| 191 | + version (str): 版本号,格式为 "vX.X.X.X" |
| 192 | + arch (str, optional): 架构,默认为 "x64" |
| 193 | + struct (str, optional): 结构,默认为 "dir" |
| 194 | +
|
| 195 | + Returns: |
| 196 | + str: 更新文件名 |
| 197 | + """ |
| 198 | + try: |
| 199 | + metadata = await get_metadata_info_async() |
| 200 | + if not metadata: |
| 201 | + # 如果 metadata 读取失败,使用默认格式 |
| 202 | + name_format = "SecRandom-Windows-[version]-[arch]-[struct].zip" |
| 203 | + else: |
| 204 | + name_format = metadata.get( |
| 205 | + "name_format", "SecRandom-Windows-[version]-[arch]-[struct].zip" |
| 206 | + ) |
| 207 | + |
| 208 | + # 替换占位符 |
| 209 | + file_name = name_format.replace("[version]", version) |
| 210 | + file_name = file_name.replace("[arch]", arch) |
| 211 | + file_name = file_name.replace("[struct]", struct) |
| 212 | + |
| 213 | + logger.debug(f"生成更新文件名成功: {file_name}") |
| 214 | + return file_name |
| 215 | + except Exception as e: |
| 216 | + logger.error(f"生成更新文件名失败: {e}") |
| 217 | + return f"SecRandom-Windows-{version}-{arch}-{struct}.zip" |
| 218 | + |
| 219 | + |
| 220 | +def get_update_file_name(version, arch="x64", struct="dir"): |
| 221 | + """ |
| 222 | + 获取更新文件名(同步版本) |
| 223 | +
|
| 224 | + Args: |
| 225 | + version (str): 版本号,格式为 "vX.X.X.X" |
| 226 | + arch (str, optional): 架构,默认为 "x64" |
| 227 | + struct (str, optional): 结构,默认为 "dir" |
| 228 | +
|
| 229 | + Returns: |
| 230 | + str: 更新文件名 |
| 231 | + """ |
| 232 | + try: |
| 233 | + # 使用 asyncio 运行异步函数 |
| 234 | + import asyncio |
| 235 | + |
| 236 | + return asyncio.run(get_update_file_name_async(version, arch, struct)) |
| 237 | + except Exception as e: |
| 238 | + logger.error(f"生成更新文件名失败: {e}") |
| 239 | + return f"SecRandom-Windows-{version}-{arch}-{struct}.zip" |
| 240 | + |
| 241 | + |
| 242 | +def get_github_repo_url(): |
| 243 | + """ |
| 244 | + 获取 GitHub 仓库 URL |
| 245 | +
|
| 246 | + Returns: |
| 247 | + str: GitHub 仓库 URL |
| 248 | + """ |
| 249 | + return "https://github.com/Anwen-OVO/SecRandom" |
| 250 | + |
| 251 | + |
| 252 | +def get_update_check_url(): |
| 253 | + """ |
| 254 | + 获取更新检查 URL |
| 255 | +
|
| 256 | + Returns: |
| 257 | + str: 更新检查 URL |
| 258 | + """ |
| 259 | + source_url = get_update_source_url() |
| 260 | + repo_url = get_github_repo_url() |
| 261 | + # 替换 GitHub 域名为更新源域名 |
| 262 | + update_check_url = ( |
| 263 | + repo_url.replace("https://github.com", source_url) + "/raw/main/metadata.yaml" |
| 264 | + ) |
| 265 | + logger.debug(f"生成更新检查 URL 成功: {update_check_url}") |
| 266 | + return update_check_url |
0 commit comments