换位置
This commit is contained in:
+70
-24
@@ -14,6 +14,7 @@ class MainWindow(QMainWindow):
|
||||
"""主窗口。支持“无项目”启动:先显示欢迎页,打开项目后加载并显示功能页。"""
|
||||
|
||||
CONSOLE_PANEL_HEIGHT = 345
|
||||
AUTO_UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000
|
||||
|
||||
def __init__(self, config: Optional[Config] = None):
|
||||
super().__init__()
|
||||
@@ -21,6 +22,9 @@ class MainWindow(QMainWindow):
|
||||
self._project_content_widget = None # 项目内容容器,首次打开项目时创建
|
||||
self._cache_init_worker = None
|
||||
self._startup_update_check_started = False
|
||||
self._update_check_worker = None
|
||||
self._update_prompt_active = False
|
||||
self._last_prompted_update_version = ""
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
@@ -255,6 +259,9 @@ class MainWindow(QMainWindow):
|
||||
self._status_timer.timeout.connect(self._update_status_time)
|
||||
self._status_timer.start(1000)
|
||||
self._update_status_time()
|
||||
self._auto_update_timer = QTimer(self)
|
||||
self._auto_update_timer.setInterval(self.AUTO_UPDATE_CHECK_INTERVAL_MS)
|
||||
self._auto_update_timer.timeout.connect(self._start_startup_update_check)
|
||||
|
||||
# 菜单栏:保证在窗口内可见(非系统原生菜单),便于看到“文件”“帮助”
|
||||
menubar = self.menuBar()
|
||||
@@ -306,49 +313,77 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
# 首次打开后延迟检查远端版本清单,版本不一致则弹窗询问是否更新
|
||||
# 首次打开后延迟检查一次,随后每 5 分钟在后台检查远端版本清单。
|
||||
if not self._startup_update_check_started:
|
||||
self._startup_update_check_started = True
|
||||
self._auto_update_timer.start()
|
||||
QTimer.singleShot(1500, self._start_startup_update_check)
|
||||
|
||||
def _start_startup_update_check(self):
|
||||
"""启动时在后台检查远端版本清单(仅当配置了 update_url 时)"""
|
||||
"""在后台检查远端版本清单(仅当配置了 update_url 时)。"""
|
||||
info = get_version_info()
|
||||
update_url = (info.get("update_url") or "").strip()
|
||||
if not update_url:
|
||||
return
|
||||
self._startup_check_worker = UpdateCheckWorker(update_url, self)
|
||||
self._startup_check_worker.finished_signal.connect(self._on_startup_update_checked)
|
||||
self._startup_check_worker.start()
|
||||
if self._update_check_worker and self._update_check_worker.isRunning():
|
||||
return
|
||||
worker = UpdateCheckWorker(update_url, self)
|
||||
self._update_check_worker = worker
|
||||
worker.finished_signal.connect(self._on_startup_update_checked)
|
||||
worker.finished.connect(lambda w=worker: self._clear_update_check_worker(w))
|
||||
worker.finished.connect(worker.deleteLater)
|
||||
worker.start()
|
||||
|
||||
def _clear_update_check_worker(self, worker):
|
||||
if self._update_check_worker is worker:
|
||||
self._update_check_worker = None
|
||||
|
||||
def _on_startup_update_checked(self, manifest):
|
||||
"""启动检查结果:若本地版本与远端版本不一致则弹窗询问是否更新"""
|
||||
"""后台检查结果:若远端版本更高则弹窗询问是否更新。"""
|
||||
if not manifest:
|
||||
return
|
||||
current = get_current_version()
|
||||
remote_version = (manifest.get("version") or "").strip()
|
||||
if not remote_version or remote_version == current:
|
||||
if not remote_version or not version_less(current, remote_version):
|
||||
if remote_version == current:
|
||||
self._last_prompted_update_version = ""
|
||||
return
|
||||
if remote_version == self._last_prompted_update_version:
|
||||
return
|
||||
if self._update_prompt_active:
|
||||
return
|
||||
if hasattr(self, "_update_worker") and self._update_worker and self._update_worker.isRunning():
|
||||
return
|
||||
self._last_prompted_update_version = remote_version
|
||||
self._update_prompt_active = True
|
||||
release_notes = (manifest.get("release_notes") or "").strip()
|
||||
msg = f"远程版本 {remote_version} 与当前版本 {current} 不一致"
|
||||
msg = f"发现新版本 {remote_version}(当前 {current})"
|
||||
if release_notes:
|
||||
msg += f"\n\n{release_notes}"
|
||||
msg += "\n\n是否立即更新?"
|
||||
ret = QMessageBox.question(
|
||||
self,
|
||||
"检查更新",
|
||||
msg,
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.Yes,
|
||||
)
|
||||
try:
|
||||
ret = QMessageBox.question(
|
||||
self,
|
||||
"检查更新",
|
||||
msg,
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.Yes,
|
||||
)
|
||||
finally:
|
||||
self._update_prompt_active = False
|
||||
if ret != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
delta = get_delta_for_current(manifest, current)
|
||||
has_delta = delta and delta.get("patch_url") and delta.get("new_exe_sha256")
|
||||
has_delta = bool(delta)
|
||||
full_url = (manifest.get("full_installer_url") or manifest.get("download_url") or "").strip()
|
||||
self._update_manifest = manifest # 保存 manifest,增量失败时可用来发起全量更新
|
||||
if has_delta:
|
||||
self._start_update_download(delta["patch_url"], use_delta=True, expected_sha256=delta.get("new_exe_sha256"))
|
||||
self._start_update_download(
|
||||
get_delta_download_url(delta),
|
||||
use_delta=True,
|
||||
expected_sha256=get_delta_expected_sha256(delta),
|
||||
delta_kind=get_delta_kind(delta),
|
||||
)
|
||||
elif full_url:
|
||||
self._start_update_download(full_url, use_delta=False)
|
||||
else:
|
||||
@@ -411,6 +446,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def _on_close_project(self):
|
||||
self.config.tool_dir = None
|
||||
self.config.user_config_path = None
|
||||
self.config.tool_config_path = None
|
||||
self.config.config_error = "未打开项目"
|
||||
self.config.data = _empty_config_data()
|
||||
@@ -465,7 +501,7 @@ class MainWindow(QMainWindow):
|
||||
release_notes = manifest.get("release_notes", "")
|
||||
full_url = (manifest.get("full_installer_url") or manifest.get("download_url") or "").strip()
|
||||
delta = get_delta_for_current(manifest, current)
|
||||
has_delta = bool(delta and delta.get("patch_url") and delta.get("new_exe_sha256"))
|
||||
has_delta = bool(delta)
|
||||
if not full_url and not has_delta:
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
@@ -492,9 +528,10 @@ class MainWindow(QMainWindow):
|
||||
self._update_manifest = manifest
|
||||
if clicked == btn_delta and has_delta:
|
||||
self._start_update_download(
|
||||
delta["patch_url"],
|
||||
get_delta_download_url(delta),
|
||||
use_delta=True,
|
||||
expected_sha256=delta.get("new_exe_sha256"),
|
||||
expected_sha256=get_delta_expected_sha256(delta),
|
||||
delta_kind=get_delta_kind(delta),
|
||||
)
|
||||
else:
|
||||
self._start_update_download(full_url, use_delta=False)
|
||||
@@ -504,12 +541,17 @@ class MainWindow(QMainWindow):
|
||||
download_url: str,
|
||||
use_delta: bool = False,
|
||||
expected_sha256: Optional[str] = None,
|
||||
delta_kind: str = "",
|
||||
):
|
||||
"""下载更新包(全量 exe 或增量 patch),完成后全量则启动安装,增量则 bsdiff 打补丁并替换"""
|
||||
dest = Path(tempfile.gettempdir()) / "ServerManager_Update"
|
||||
dest.mkdir(parents=True, exist_ok=True)
|
||||
suffix = Path(download_url).suffix or (".patch" if use_delta else ".exe")
|
||||
from urllib.parse import urlparse
|
||||
suffix = Path(urlparse(download_url).path).suffix
|
||||
if not suffix:
|
||||
suffix = ".smdelta" if use_delta and delta_kind == "file_zip" else (".patch" if use_delta else ".exe")
|
||||
dest_file = dest / ("ServerManager_patch" + suffix if use_delta else f"ServerManager_Setup{suffix}")
|
||||
self._update_delta_kind = delta_kind
|
||||
self._update_download_path = dest_file
|
||||
self._update_progress = QProgressDialog("正在下载更新...", "取消", 0, 100, self)
|
||||
self._update_progress.setWindowTitle("检查更新")
|
||||
@@ -542,13 +584,17 @@ class MainWindow(QMainWindow):
|
||||
if not path or not Path(path).exists():
|
||||
QMessageBox.warning(self, "检查更新", "下载失败,请稍后重试或手动下载。")
|
||||
return
|
||||
if is_delta and expected_sha256:
|
||||
if is_delta:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"检查更新",
|
||||
"增量包已下载,即将退出并重启以应用补丁。"
|
||||
"增量包已下载,即将退出并重启以应用更新。"
|
||||
)
|
||||
ok, reason = apply_delta_patch(Path(path), expected_sha256)
|
||||
delta_kind = getattr(self, "_update_delta_kind", "") or "bsdiff_exe"
|
||||
if delta_kind == "file_zip":
|
||||
ok, reason = apply_file_delta_package(Path(path), expected_sha256 or "")
|
||||
else:
|
||||
ok, reason = apply_delta_patch(Path(path), expected_sha256 or "")
|
||||
if ok:
|
||||
pass # 成功时进程会退出
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user