Skip to content

Commit 6a52b2b

Browse files
committed
制作更新检查逻辑
1 parent 65f1db5 commit 6a52b2b

3 files changed

Lines changed: 274 additions & 6 deletions

File tree

app/tools/update_utils.py

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
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

app/view/settings/update.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ def setup_update_settings(self):
106106
# 自动下载更新开关
107107
self.auto_download_switch = SwitchButton()
108108
self.auto_download_switch.setOffText(
109-
get_content_name_async("update", "auto_download", "disable")
109+
get_content_switchbutton_name_async("update", "auto_download", "disable")
110110
)
111111
self.auto_download_switch.setOnText(
112-
get_content_name_async("update", "auto_download", "enable")
112+
get_content_switchbutton_name_async("update", "auto_download", "enable")
113113
)
114114
auto_download = readme_settings("update", "auto_download")
115115
self.auto_download_switch.setChecked(auto_download)
@@ -122,10 +122,10 @@ def setup_update_settings(self):
122122
# 自动安装更新开关
123123
self.auto_update_switch = SwitchButton()
124124
self.auto_update_switch.setOffText(
125-
get_content_name_async("update", "auto_update", "disable")
125+
get_content_switchbutton_name_async("update", "auto_update", "disable")
126126
)
127127
self.auto_update_switch.setOnText(
128-
get_content_name_async("update", "auto_update", "enable")
128+
get_content_switchbutton_name_async("update", "auto_update", "enable")
129129
)
130130
auto_update = readme_settings("update", "auto_update")
131131
self.auto_update_switch.setChecked(auto_update)
@@ -138,10 +138,12 @@ def setup_update_settings(self):
138138
# 更新通知开关
139139
self.need_notification_switch = SwitchButton()
140140
self.need_notification_switch.setOffText(
141-
get_content_name_async("update", "need_notification", "disable")
141+
get_content_switchbutton_name_async(
142+
"update", "need_notification", "disable"
143+
)
142144
)
143145
self.need_notification_switch.setOnText(
144-
get_content_name_async("update", "need_notification", "enable")
146+
get_content_switchbutton_name_async("update", "need_notification", "enable")
145147
)
146148
need_notification = readme_settings("update", "need_notification")
147149
self.need_notification_switch.setChecked(need_notification)
File renamed without changes.

0 commit comments

Comments
 (0)