From cb5f900c3960cb0aa982b6d7bda17f6eade5c587 Mon Sep 17 00:00:00 2001 From: qinglong Date: Sun, 14 Jun 2026 10:45:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E6=97=A5=E5=BF=97=20=E2=80=94=20SSE=E8=BD=AE?= =?UTF-8?q?=E8=AF=A2=20+=20logs/updates=5Flogs=20=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/update_service.py | 29 +++++++++++++++++++++++++++- static/web_panel/pages/settings.html | 5 +++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/services/update_service.py b/services/update_service.py index 74b0f08..54f4774 100644 --- a/services/update_service.py +++ b/services/update_service.py @@ -76,6 +76,18 @@ class UpdateService: self.sm = service_manager self._task: Optional[asyncio.Task] = None self._running = False + # 日志目录 + import logging as _logging + self.update_logger = _logging.getLogger("senSu.update") + log_dir = _PROJECT_ROOT / "logs" / "updates_logs" + log_dir.mkdir(parents=True, exist_ok=True) + fh = _logging.FileHandler( + log_dir / f"update_{time.strftime('%Y%m%d_%H%M%S')}.log", + encoding='utf-8' + ) + fh.setFormatter(_logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')) + self.update_logger.addHandler(fh) + self.update_logger.setLevel(_logging.INFO) self.status: dict = {"state": "idle", "progress": 0, "error": "", "last_check": 0, "checked": False, "update_available": False, "current_version": "", "latest_version": ""} @@ -179,8 +191,10 @@ class UpdateService: url = self.download_url logger.info(f"📥 下载更新包: {url}") + self._log("开始更新...") # 0. 备份当前版本 self.status["progress"] = 2 + self._log("创建备份...") backup_name = f"SenSu_backup_{self._current_version()}_{time.strftime('%Y%m%d_%H%M%S')}.zip" backup_dir = _PROJECT_ROOT / "data" / "backups" backup_dir.mkdir(parents=True, exist_ok=True) @@ -199,12 +213,14 @@ class UpdateService: with urllib.request.urlopen(req, timeout=300) as resp: shutil.copyfileobj(resp, tmp_zip) tmp_zip.close() + self._log("下载完成") self.status["progress"] = 40 # 2. 解压到临时目录 tmp_dir = tempfile.mkdtemp() with zipfile.ZipFile(tmp_zip.name, "r") as zf: zf.extractall(tmp_dir) + self._log("解压更新包...") self.status["progress"] = 60 # 3. Gitea zip 内层目录: 通常是 repo_name-branch/ @@ -229,6 +245,7 @@ class UpdateService: os.makedirs(os.path.dirname(dst), exist_ok=True) shutil.copy2(src, dst) + self._log("覆盖文件 (跳过用户配置)...") self.status["progress"] = 80 # 4.5 同步版本号到旧配置文件 @@ -246,10 +263,12 @@ class UpdateService: old_cfg.setdefault("framework", {})["version"] = new_ver with open(old_cfg_path, "w") as f: _yaml.dump(old_cfg, f, default_flow_style=False, allow_unicode=True) - logger.info(f"📝 版本号已同步: {new_ver}") + self._log(f"版本号已同步: {new_ver}") + logger.info(f"📝 版本号已同步: {new_ver}") except Exception as e: logger.warning(f"版本号同步失败: {e}") + self._log("安装依赖...") # 5. 安装依赖 (子进程) req_file = str(_PROJECT_ROOT / "requirements.txt") if os.path.exists(req_file): @@ -259,12 +278,15 @@ class UpdateService: cwd=str(_PROJECT_ROOT), ) if r.returncode != 0: + self._log(f"依赖安装警告: {r.stderr[-200:]}") logger.warning(f"依赖安装警告: {r.stderr[-300:]}") self.status["progress"] = 100 + self._log("更新完成, 框架将重启") return {"ok": True, "msg": "更新完成, 框架将重启"} except Exception as e: + self._log(f"更新失败: {e}") logger.error(f"更新失败: {e}") return {"ok": False, "error": str(e)} finally: @@ -273,6 +295,11 @@ class UpdateService: if tmp_dir and os.path.exists(tmp_dir): shutil.rmtree(tmp_dir, ignore_errors=True) + def _log(self, msg: str): + """写入更新日志 + 更新SSE状态""" + self.update_logger.info(msg) + self.status["log"] = self.status.get("log", "") + msg + "\n" + async def check_now(self): await self._check_version() diff --git a/static/web_panel/pages/settings.html b/static/web_panel/pages/settings.html index 57ea3a8..f1e41a1 100644 --- a/static/web_panel/pages/settings.html +++ b/static/web_panel/pages/settings.html @@ -22,6 +22,10 @@
加载中...
+ @@ -134,6 +138,7 @@ setTimeout(loadVersion, 1500); } + var _updatePollTimer=null; async function applyUpdate() { if (!confirm("确认更新 SenSu?更新前会自动备份当前版本。")) return; document.getElementById("btn-apply").disabled = true;