feat:启动时检查webui版本并尝试自动更新
This commit is contained in:
@@ -5,29 +5,28 @@
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from importlib.metadata import PackageNotFoundError, version as get_package_version
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
import httpx
|
||||
import os
|
||||
import time
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.config.config import MMC_VERSION
|
||||
from src.webui.dashboard_update import (
|
||||
DASHBOARD_PACKAGE_NAME,
|
||||
PYPI_PROJECT_URL,
|
||||
detect_package_runner,
|
||||
get_dashboard_version_info,
|
||||
)
|
||||
from src.webui.dependencies import require_auth
|
||||
|
||||
router = APIRouter(prefix="/system", tags=["system"], dependencies=[Depends(require_auth)])
|
||||
logger = get_logger("webui_system")
|
||||
|
||||
# 记录启动时间
|
||||
_start_time = time.time()
|
||||
_DASHBOARD_PACKAGE_NAME = "maibot-dashboard"
|
||||
_PYPI_JSON_URL = f"https://pypi.org/pypi/{_DASHBOARD_PACKAGE_NAME}/json"
|
||||
_PYPI_CACHE_TTL_SECONDS = 60 * 60 * 6
|
||||
_pypi_version_cache: Dict[str, Any] = {"checked_at": 0.0, "latest_version": None}
|
||||
|
||||
|
||||
class RestartResponse(BaseModel):
|
||||
@@ -52,64 +51,9 @@ class DashboardVersionResponse(BaseModel):
|
||||
current_version: str
|
||||
latest_version: Optional[str] = None
|
||||
has_update: bool = False
|
||||
package_name: str = _DASHBOARD_PACKAGE_NAME
|
||||
pypi_url: str = f"https://pypi.org/project/{_DASHBOARD_PACKAGE_NAME}/"
|
||||
|
||||
|
||||
def _get_installed_dashboard_version() -> str:
|
||||
try:
|
||||
return get_package_version(_DASHBOARD_PACKAGE_NAME)
|
||||
except PackageNotFoundError:
|
||||
return "unknown"
|
||||
|
||||
|
||||
def _normalize_version(version: str) -> tuple[int, ...]:
|
||||
clean_version = version.strip().lower().removeprefix("v")
|
||||
numeric_part = clean_version.split("-", 1)[0].split("+", 1)[0]
|
||||
parts = []
|
||||
for item in numeric_part.split("."):
|
||||
number = ""
|
||||
for char in item:
|
||||
if not char.isdigit():
|
||||
break
|
||||
number += char
|
||||
parts.append(int(number) if number else 0)
|
||||
return tuple(parts)
|
||||
|
||||
|
||||
def _is_newer_version(latest_version: Optional[str], current_version: str) -> bool:
|
||||
if not latest_version or not current_version or current_version == "unknown":
|
||||
return False
|
||||
|
||||
latest_parts = _normalize_version(latest_version)
|
||||
current_parts = _normalize_version(current_version)
|
||||
width = max(len(latest_parts), len(current_parts))
|
||||
return latest_parts + (0,) * (width - len(latest_parts)) > current_parts + (0,) * (width - len(current_parts))
|
||||
|
||||
|
||||
async def _get_latest_dashboard_version_from_pypi() -> Optional[str]:
|
||||
now = time.time()
|
||||
cached_version = _pypi_version_cache.get("latest_version")
|
||||
checked_at = float(_pypi_version_cache.get("checked_at", 0.0))
|
||||
if cached_version and now - checked_at < _PYPI_CACHE_TTL_SECONDS:
|
||||
return str(cached_version)
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
response = await client.get(_PYPI_JSON_URL)
|
||||
response.raise_for_status()
|
||||
payload = response.json()
|
||||
except Exception as e:
|
||||
logger.debug(f"检查 WebUI PyPI 版本失败: {e}")
|
||||
return str(cached_version) if cached_version else None
|
||||
|
||||
latest_version = payload.get("info", {}).get("version")
|
||||
if isinstance(latest_version, str) and latest_version.strip():
|
||||
_pypi_version_cache["checked_at"] = now
|
||||
_pypi_version_cache["latest_version"] = latest_version.strip()
|
||||
return latest_version.strip()
|
||||
|
||||
return str(cached_version) if cached_version else None
|
||||
runner: str = "unknown"
|
||||
package_name: str = DASHBOARD_PACKAGE_NAME
|
||||
pypi_url: str = PYPI_PROJECT_URL
|
||||
|
||||
|
||||
@router.post("/restart", response_model=RestartResponse)
|
||||
@@ -166,13 +110,13 @@ async def get_maibot_status():
|
||||
@router.get("/dashboard-version", response_model=DashboardVersionResponse)
|
||||
async def get_dashboard_version(current_version: Optional[str] = None):
|
||||
"""获取 WebUI 当前版本和 PyPI 最新版本。"""
|
||||
resolved_current_version = current_version or _get_installed_dashboard_version()
|
||||
latest_version = await _get_latest_dashboard_version_from_pypi()
|
||||
version_info = await get_dashboard_version_info(current_version)
|
||||
|
||||
return DashboardVersionResponse(
|
||||
current_version=resolved_current_version,
|
||||
latest_version=latest_version,
|
||||
has_update=_is_newer_version(latest_version, resolved_current_version),
|
||||
current_version=version_info.current_version,
|
||||
latest_version=version_info.latest_version,
|
||||
has_update=version_info.has_update,
|
||||
runner=detect_package_runner(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user