|
| 1 | +import asyncio |
1 | 2 | import logging |
2 | 3 | from contextlib import asynccontextmanager |
3 | 4 |
|
|
8 | 9 | from module.core import Program |
9 | 10 | from module.models import APIResponse |
10 | 11 | from module.models.response import ResponseModel |
11 | | -from module.security.api import UNAUTHORIZED, get_current_user |
| 12 | +from module.security.api import get_current_user |
| 13 | +from module.update import ReleaseChecker |
12 | 14 |
|
13 | 15 | from .response import u_response |
14 | 16 |
|
@@ -128,4 +130,129 @@ async def shutdown_program(): |
128 | 130 | dependencies=[Depends(get_current_user)], |
129 | 131 | ) |
130 | 132 | async def check_downloader_status(): |
131 | | - return await program.program_status.check_downloader() |
| 133 | + return program.program_status.check_downloader() |
| 134 | + |
| 135 | + |
| 136 | +# Check for updates |
| 137 | +@router.get( |
| 138 | + "/check/update", |
| 139 | + tags=["update"], |
| 140 | + response_model=dict, |
| 141 | + dependencies=[Depends(get_current_user)], |
| 142 | +) |
| 143 | +async def check_for_update(include_prerelease: bool = False): |
| 144 | + """检查是否有可用的版本更新 |
| 145 | +
|
| 146 | + Args: |
| 147 | + include_prerelease: 是否包含预发布版本 |
| 148 | +
|
| 149 | + Returns: |
| 150 | + dict: 包含版本检查结果的字典 |
| 151 | + """ |
| 152 | + try: |
| 153 | + checker = ReleaseChecker("shinonomeow", "Auto_Bangumi") |
| 154 | + result = await checker.check_for_update(include_prerelease=True) |
| 155 | + return result |
| 156 | + except Exception as e: |
| 157 | + logger.error(f"Failed to check for updates: {e}") |
| 158 | + raise HTTPException( |
| 159 | + status_code=500, |
| 160 | + detail={"msg_en": "Failed to check for updates.", "msg_zh": "检查更新失败。", "error": str(e)}, |
| 161 | + ) |
| 162 | + |
| 163 | + |
| 164 | +@router.post("/update", response_model=APIResponse, dependencies=[Depends(get_current_user)]) |
| 165 | +async def update_program(download_url: str): |
| 166 | + """Docker 环境更新接口 |
| 167 | +
|
| 168 | + Args: |
| 169 | + download_url: 更新包下载 URL(必须是 GitHub releases) |
| 170 | +
|
| 171 | + Returns: |
| 172 | + APIResponse: 更新结果 |
| 173 | + """ |
| 174 | + try: |
| 175 | + # 检测是否在 Docker 环境 |
| 176 | + from module.utils.environment import is_docker_environment |
| 177 | + |
| 178 | + if not is_docker_environment(): |
| 179 | + raise HTTPException( |
| 180 | + status_code=400, |
| 181 | + detail={ |
| 182 | + "msg_en": "Update only supported in Docker environment.", |
| 183 | + "msg_zh": "更新功能仅支持 Docker 环境。", |
| 184 | + }, |
| 185 | + ) |
| 186 | + |
| 187 | + # 导入更新器 |
| 188 | + from module.update import docker_updater |
| 189 | + |
| 190 | + # 创建异步任务执行更新 |
| 191 | + async def perform_update(): |
| 192 | + try: |
| 193 | + # 等待一小段时间让 API 响应返回 |
| 194 | + await asyncio.sleep(1) |
| 195 | + |
| 196 | + logger.info(f"[Program] Starting update from URL: {download_url}") |
| 197 | + |
| 198 | + # 停止应用核心 |
| 199 | + await program.stop() |
| 200 | + |
| 201 | + # 执行更新 |
| 202 | + await docker_updater.update(download_url) |
| 203 | + |
| 204 | + # 强制重启容器 |
| 205 | + docker_updater.force_restart() |
| 206 | + |
| 207 | + except Exception as e: |
| 208 | + logger.error(f"[Program] Update failed: {e}") |
| 209 | + # 尝试重启应用核心 |
| 210 | + try: |
| 211 | + await program.start() |
| 212 | + except Exception as restart_error: |
| 213 | + logger.error(f"[Program] Failed to restart after update failure: {restart_error}") |
| 214 | + |
| 215 | + # 启动异步更新任务 |
| 216 | + asyncio.create_task(perform_update()) |
| 217 | + |
| 218 | + # 立即返回响应 |
| 219 | + return u_response( |
| 220 | + ResponseModel( |
| 221 | + status=True, |
| 222 | + status_code=200, |
| 223 | + msg_en="Update started successfully. Container will restart shortly.", |
| 224 | + msg_zh="更新已开始。容器将很快重启。", |
| 225 | + data={"download_url": download_url}, |
| 226 | + ) |
| 227 | + ) |
| 228 | + |
| 229 | + except HTTPException: |
| 230 | + raise |
| 231 | + except Exception as e: |
| 232 | + logger.error(f"[Program] Update initiation failed: {e}") |
| 233 | + raise HTTPException( |
| 234 | + status_code=500, |
| 235 | + detail={"msg_en": "Failed to start update process.", "msg_zh": "启动更新进程失败。", "error": str(e)}, |
| 236 | + ) |
| 237 | + |
| 238 | + |
| 239 | +# Update status check |
| 240 | +@router.get("/update/status", response_model=dict, dependencies=[Depends(get_current_user)]) |
| 241 | +async def get_update_status(): |
| 242 | + """获取更新状态 |
| 243 | +
|
| 244 | + Returns: |
| 245 | + dict: 更新状态信息 |
| 246 | + """ |
| 247 | + import os |
| 248 | + |
| 249 | + from module.utils.environment import get_environment_info, is_docker_environment |
| 250 | + |
| 251 | + # 检查是否有更新锁文件 |
| 252 | + update_lock_exists = os.path.exists("/tmp/auto_bangumi_update.lock") |
| 253 | + |
| 254 | + return { |
| 255 | + "update_in_progress": update_lock_exists, |
| 256 | + "environment": get_environment_info(), |
| 257 | + "update_supported": is_docker_environment(), |
| 258 | + } |
0 commit comments