🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
206 lines
5.6 KiB
Python
206 lines
5.6 KiB
Python
"""Update management API endpoints.
|
|
|
|
Refactored to use UpdateService for all business logic.
|
|
Endpoints are now thin adapters that convert HTTP requests/responses.
|
|
"""
|
|
from typing import Optional
|
|
from fastapi import APIRouter, HTTPException
|
|
from pydantic import BaseModel
|
|
|
|
from ..services.container import container
|
|
from ..managers.ble_manager import get_ble_manager, NotificationType
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class UpdateCheckResponse(BaseModel):
|
|
"""Response model for update check."""
|
|
update_available: bool
|
|
current_version: str
|
|
latest_version: Optional[str] = None
|
|
release_date: Optional[str] = None
|
|
changelog: Optional[str] = None
|
|
is_prerelease: bool = False
|
|
download_size: Optional[int] = None
|
|
message: Optional[str] = None
|
|
|
|
|
|
class UpdateProgressResponse(BaseModel):
|
|
"""Response model for update progress."""
|
|
status: str
|
|
current_version: str
|
|
available_version: Optional[str] = None
|
|
download_progress: float = 0.0
|
|
error_message: Optional[str] = None
|
|
last_check: Optional[str] = None
|
|
|
|
|
|
class ReleaseNotesRequest(BaseModel):
|
|
"""Request model for release notes."""
|
|
version: Optional[str] = None
|
|
|
|
|
|
def _service_error_to_http_status(error_code: str) -> int:
|
|
"""Map service error codes to HTTP status codes.
|
|
|
|
Args:
|
|
error_code: Service error code
|
|
|
|
Returns:
|
|
HTTP status code
|
|
"""
|
|
codes = {
|
|
"update_check_error": 500,
|
|
"no_update_available": 400,
|
|
"download_failed": 500,
|
|
"update_download_error": 500,
|
|
"no_update_downloaded": 400,
|
|
"installation_failed": 500,
|
|
"update_install_error": 500,
|
|
"progress_error": 500,
|
|
"release_notes_error": 500,
|
|
"check_download_error": 500,
|
|
"full_update_error": 500,
|
|
}
|
|
return codes.get(error_code, 500)
|
|
|
|
|
|
@router.get("/check", response_model=UpdateCheckResponse)
|
|
async def check_for_updates():
|
|
"""Check for available updates.
|
|
|
|
Uses UpdateService for business logic.
|
|
"""
|
|
result = await container.update_service.check_for_updates()
|
|
|
|
if not result.success:
|
|
raise HTTPException(
|
|
status_code=_service_error_to_http_status(result.error.code),
|
|
detail=result.error.message
|
|
)
|
|
|
|
# Send BLE notification if update is available
|
|
if result.data.get("update_available"):
|
|
try:
|
|
ble_manager = get_ble_manager()
|
|
await ble_manager.send_notification(
|
|
NotificationType.UPDATE_AVAILABLE,
|
|
f"Update available: v{result.data['latest_version']}",
|
|
{"version": result.data["latest_version"]}
|
|
)
|
|
except Exception:
|
|
# BLE notification failure shouldn't affect the response
|
|
pass
|
|
|
|
return UpdateCheckResponse(**result.data)
|
|
|
|
|
|
@router.get("/progress", response_model=UpdateProgressResponse)
|
|
async def get_update_progress():
|
|
"""Get current update progress.
|
|
|
|
Uses UpdateService for business logic.
|
|
"""
|
|
result = await container.update_service.get_progress()
|
|
|
|
if not result.success:
|
|
raise HTTPException(
|
|
status_code=_service_error_to_http_status(result.error.code),
|
|
detail=result.error.message
|
|
)
|
|
|
|
return UpdateProgressResponse(**result.data)
|
|
|
|
|
|
@router.post("/download")
|
|
async def download_update():
|
|
"""Download the available update.
|
|
|
|
Uses UpdateService for business logic.
|
|
"""
|
|
result = await container.update_service.download_update()
|
|
|
|
if not result.success:
|
|
raise HTTPException(
|
|
status_code=_service_error_to_http_status(result.error.code),
|
|
detail=result.error.message
|
|
)
|
|
|
|
return {"message": result.data["message"]}
|
|
|
|
|
|
@router.post("/install")
|
|
async def install_update():
|
|
"""Install the downloaded update.
|
|
|
|
Uses UpdateService for business logic.
|
|
"""
|
|
result = await container.update_service.install_update()
|
|
|
|
if not result.success:
|
|
raise HTTPException(
|
|
status_code=_service_error_to_http_status(result.error.code),
|
|
detail=result.error.message
|
|
)
|
|
|
|
# Send BLE notification
|
|
try:
|
|
ble_manager = get_ble_manager()
|
|
await ble_manager.send_notification(
|
|
NotificationType.UPDATE_COMPLETE,
|
|
"Update installed successfully",
|
|
{"restart_required": True}
|
|
)
|
|
except Exception:
|
|
# BLE notification failure shouldn't affect the response
|
|
pass
|
|
|
|
return {
|
|
"message": result.data["message"],
|
|
"restart_required": result.data.get("requires_restart", True)
|
|
}
|
|
|
|
|
|
@router.post("/release-notes", response_model=dict)
|
|
async def get_release_notes(request: ReleaseNotesRequest):
|
|
"""Get release notes for a specific version.
|
|
|
|
Uses UpdateService for business logic.
|
|
|
|
Args:
|
|
request: Version to get notes for (latest if not specified)
|
|
"""
|
|
result = await container.update_service.get_release_notes(request.version)
|
|
|
|
if not result.success:
|
|
raise HTTPException(
|
|
status_code=_service_error_to_http_status(result.error.code),
|
|
detail=result.error.message
|
|
)
|
|
|
|
return {
|
|
"version": result.data["version"],
|
|
"notes": result.data["release_notes"]
|
|
}
|
|
|
|
|
|
@router.get("/current-version")
|
|
async def get_current_version():
|
|
"""Get current system version.
|
|
|
|
Uses UpdateService for business logic.
|
|
"""
|
|
result = await container.update_service.get_progress()
|
|
|
|
if not result.success:
|
|
raise HTTPException(
|
|
status_code=_service_error_to_http_status(result.error.code),
|
|
detail=result.error.message
|
|
)
|
|
|
|
return {
|
|
"version": result.data["current_version"],
|
|
"last_check": result.data["last_check"]
|
|
}
|