diff --git a/.github/workflows/smoke_test.yml b/.github/workflows/smoke_test.yml index 52b9a29b7..8e629c5af 100644 --- a/.github/workflows/smoke_test.yml +++ b/.github/workflows/smoke_test.yml @@ -39,7 +39,9 @@ jobs: - name: Run smoke tests run: | - uv run main.py & + # uv run main.py & + uv tool install -e . --force + astrbot run --backend-only APP_PID=$! echo "Waiting for application to start..." diff --git a/astrbot/cli/utils/basic.py b/astrbot/cli/utils/basic.py index b90fd6e11..673baaec9 100644 --- a/astrbot/cli/utils/basic.py +++ b/astrbot/cli/utils/basic.py @@ -45,13 +45,16 @@ async def check_dashboard(astrbot_root: Path) -> None: abort=True, ): click.echo("Installing dashboard...") - await download_dashboard( - path="data/dashboard.zip", - extract_path=str(astrbot_root / "data"), - version=f"v{VERSION}", - latest=False, - ) - click.echo("Dashboard installed successfully") + try: + await download_dashboard( + path="data/dashboard.zip", + extract_path=str(astrbot_root / "data"), + version=f"v{VERSION}", + latest=False, + ) + click.echo("Dashboard installed successfully") + except Exception as e: + click.echo(f"Failed to install dashboard: {e}") case str(): if VersionComparator.compare_version(VERSION, dashboard_version) <= 0: diff --git a/astrbot/core/utils/io.py b/astrbot/core/utils/io.py index f9ad47dbf..a008740fb 100644 --- a/astrbot/core/utils/io.py +++ b/astrbot/core/utils/io.py @@ -285,35 +285,107 @@ async def download_dashboard( else: zip_path = Path(path).absolute() - if latest or len(str(version)) != 40: - ver_name = "latest" if latest else version - dashboard_release_url = f"https://astrbot-registry.soulter.top/download/astrbot-dashboard/{ver_name}/dist.zip" - logger.info( - f"准备下载指定发行版本的 AstrBot WebUI 文件: {dashboard_release_url}", - ) - try: - await download_file( - dashboard_release_url, - str(zip_path), - show_progress=True, + # 缓存机制 + cache_dir = Path(get_astrbot_data_path()).absolute() / "cache" + if not cache_dir.exists(): + cache_dir.mkdir(parents=True, exist_ok=True) + + use_cache = False + + # Only use cache if not requesting "latest" (we don't know the version yet) + if not latest and version: + cache_name = f"dashboard_{version}.zip" + cache_path = cache_dir / cache_name + + if cache_path.exists(): + logger.info(f"发现本地缓存的管理面板文件: {cache_path}") + try: + with zipfile.ZipFile(cache_path, "r") as z: + if z.testzip() is None: + logger.info("缓存文件校验通过,将直接使用缓存。") + if str(cache_path) != str(zip_path): + shutil.copy(cache_path, zip_path) + use_cache = True + else: + logger.warning("缓存文件损坏,将重新下载。") + os.remove(cache_path) + except zipfile.BadZipFile: + logger.warning("缓存文件损坏 (BadZipFile),将重新下载。") + os.remove(cache_path) + + if not use_cache: + if latest or len(str(version)) != 40: + ver_name = "latest" if latest else version + dashboard_release_url = f"https://astrbot-registry.soulter.top/download/astrbot-dashboard/{ver_name}/dist.zip" + logger.info( + f"准备下载指定发行版本的 AstrBot WebUI 文件: {dashboard_release_url}", ) - except BaseException as _: - if latest: - dashboard_release_url = "https://github.com/AstrBotDevs/AstrBot/releases/latest/download/dist.zip" - else: - dashboard_release_url = f"https://github.com/AstrBotDevs/AstrBot/releases/download/{version}/dist.zip" + try: + await download_file( + dashboard_release_url, + str(zip_path), + show_progress=True, + ) + except BaseException as _: + try: + if latest: + dashboard_release_url = "https://github.com/AstrBotDevs/AstrBot/releases/latest/download/dist.zip" + else: + dashboard_release_url = f"https://github.com/AstrBotDevs/AstrBot/releases/download/{version}/dist.zip" + if proxy: + dashboard_release_url = f"{proxy}/{dashboard_release_url}" + await download_file( + dashboard_release_url, + str(zip_path), + show_progress=True, + ) + except Exception as e: + if not latest: + logger.warning( + f"下载指定版本({version})失败: {e},尝试下载最新版本。" + ) + await download_dashboard( + path=path, + extract_path=extract_path, + latest=True, + proxy=proxy, + ) + return + raise e + else: + url = f"https://github.com/AstrBotDevs/astrbot-release-harbour/releases/download/release-{version}/dist.zip" + logger.info(f"准备下载指定版本的 AstrBot WebUI: {url}") if proxy: - dashboard_release_url = f"{proxy}/{dashboard_release_url}" - await download_file( - dashboard_release_url, - str(zip_path), - show_progress=True, - ) - else: - url = f"https://github.com/AstrBotDevs/astrbot-release-harbour/releases/download/release-{version}/dist.zip" - logger.info(f"准备下载指定版本的 AstrBot WebUI: {url}") - if proxy: - url = f"{proxy}/{url}" - await download_file(url, str(zip_path), show_progress=True) + url = f"{proxy}/{url}" + await download_file(url, str(zip_path), show_progress=True) + + # 下载完成后存入缓存 + try: + save_cache_name = None + if not latest and version: + save_cache_name = f"dashboard_{version}.zip" + else: + # 尝试从下载的文件中读取版本号 + try: + with zipfile.ZipFile(zip_path, "r") as z: + for v_path in ["dist/assets/version", "assets/version"]: + try: + with z.open(v_path) as f: + v = f.read().decode("utf-8").strip() + save_cache_name = f"dashboard_{v}.zip" + break + except KeyError: + continue + except Exception: + pass + + if save_cache_name: + cache_save_path = cache_dir / save_cache_name + if str(zip_path) != str(cache_save_path): + shutil.copy(zip_path, cache_save_path) + logger.info(f"已缓存管理面板文件至: {cache_save_path}") + except Exception as e: + logger.warning(f"缓存管理面板文件失败: {e}") + with zipfile.ZipFile(zip_path, "r") as z: z.extractall(extract_path)