Initial commit - Phase 3/4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
michael
2026-01-06 13:45:29 -08:00
parent 1da6730735
commit 4f35df1781
323 changed files with 98287 additions and 1195 deletions

View File

@@ -1,9 +1,13 @@
"""Update management API endpoints."""
"""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 ..managers.update_manager import get_update_manager, UpdateStatus
from ..services.container import container
from ..managers.ble_manager import get_ble_manager, NotificationType
@@ -37,149 +41,165 @@ class ReleaseNotesRequest(BaseModel):
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.
Returns:
UpdateCheckResponse with update status and info
Uses UpdateService for business logic.
"""
try:
manager = get_update_manager()
ble_manager = get_ble_manager()
result = await manager.check_for_updates()
result = await container.update_service.check_for_updates()
# Send BLE notification if update is available
if result.get("update_available"):
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['latest_version']}",
{"version": result["latest_version"]}
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)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return UpdateCheckResponse(**result.data)
@router.get("/progress", response_model=UpdateProgressResponse)
async def get_update_progress():
"""Get current update progress.
Returns:
UpdateProgressResponse with current status
Uses UpdateService for business logic.
"""
try:
manager = get_update_manager()
progress = await manager.get_progress()
result = await container.update_service.get_progress()
return UpdateProgressResponse(
status=progress.status.value,
current_version=progress.current_version,
available_version=progress.available_version,
download_progress=progress.download_progress,
error_message=progress.error_message,
last_check=progress.last_check
if not result.success:
raise HTTPException(
status_code=_service_error_to_http_status(result.error.code),
detail=result.error.message
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return UpdateProgressResponse(**result.data)
@router.post("/download")
async def download_update():
"""Download the available update.
Returns:
Success message
Uses UpdateService for business logic.
"""
try:
manager = get_update_manager()
success = await manager.download_update()
result = await container.update_service.download_update()
if success:
return {"message": "Update downloaded successfully"}
else:
raise HTTPException(status_code=500, detail="Download failed")
if not result.success:
raise HTTPException(
status_code=_service_error_to_http_status(result.error.code),
detail=result.error.message
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return {"message": result.data["message"]}
@router.post("/install")
async def install_update():
"""Install the downloaded update.
Returns:
Success message
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:
manager = get_update_manager()
ble_manager = get_ble_manager()
success = await manager.install_update()
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
if success:
# Send BLE notification
await ble_manager.send_notification(
NotificationType.UPDATE_COMPLETE,
"Update installed successfully",
{"restart_required": True}
)
return {
"message": "Update installed successfully. Please restart the service.",
"restart_required": True
}
else:
raise HTTPException(status_code=500, detail="Installation failed")
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
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)
Returns:
Release notes as markdown
"""
try:
manager = get_update_manager()
notes = await manager.get_release_notes(request.version)
result = await container.update_service.get_release_notes(request.version)
return {
"version": request.version or "latest",
"notes": notes
}
if not result.success:
raise HTTPException(
status_code=_service_error_to_http_status(result.error.code),
detail=result.error.message
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return {
"version": result.data["version"],
"notes": result.data["release_notes"]
}
@router.get("/current-version")
async def get_current_version():
"""Get current system version.
Returns:
Current version info
Uses UpdateService for business logic.
"""
try:
manager = get_update_manager()
progress = await manager.get_progress()
result = await container.update_service.get_progress()
return {
"version": progress.current_version,
"last_check": progress.last_check
}
if not result.success:
raise HTTPException(
status_code=_service_error_to_http_status(result.error.code),
detail=result.error.message
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return {
"version": result.data["current_version"],
"last_check": result.data["last_check"]
}