feat: 更新页面实时日志 — SSE轮询 + logs/updates_logs 文件记录
This commit is contained in:
@@ -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)
|
||||
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()
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
<button class="btn btn-sm btn-filled" onclick="createBackup()" style="margin-left:8px">+ 创建备份</button>
|
||||
</div>
|
||||
<div id="backup-list"><span style="color:var(--text-dim);font-size:.85rem">加载中...</span></div>
|
||||
<div id="update-log-area" style="display:none;margin-top:12px">
|
||||
<div style="font-weight:600;margin-bottom:4px">更新日志</div>
|
||||
<pre id="update-log" style="background:var(--md-sys-color-surface-container-lowest);padding:8px;border-radius:var(--shape-xs);max-height:200px;overflow-y:auto;font-size:.8rem;margin:0;white-space:pre-wrap;word-break:break-all"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -134,6 +138,7 @@
|
||||
setTimeout(loadVersion, 1500);
|
||||
}
|
||||
|
||||
var _updatePollTimer=null;
|
||||
async function applyUpdate() {
|
||||
if (!confirm("确认更新 SenSu?更新前会自动备份当前版本。")) return;
|
||||
document.getElementById("btn-apply").disabled = true;
|
||||
|
||||
Reference in New Issue
Block a user