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

@@ -0,0 +1,312 @@
"""Update Service Layer.
This service provides software update operations that can be consumed by
multiple interfaces (REST API, BLE GATT, etc.).
"""
from typing import Optional, Dict, Any
from ..managers.update_manager import UpdateManager, UpdateProgress, UpdateStatus
from .pm3_service import PM3ServiceError, PM3ServiceResult
class UpdateService:
"""Update service layer for software update management.
This service can be used by multiple interfaces:
- REST API (FastAPI endpoints)
- BLE GATT (Bluetooth handlers)
- Plugin system (future)
It encapsulates:
- Update checking
- Update downloading
- Update installation
- Progress monitoring
"""
def __init__(self, update_manager: Optional[UpdateManager] = None):
"""Initialize update service.
Args:
update_manager: Update manager instance (creates new if not provided)
"""
from ..managers.update_manager import get_update_manager
self.update_manager = update_manager or get_update_manager()
async def check_for_updates(self) -> PM3ServiceResult:
"""Check for available updates.
Returns:
PM3ServiceResult with update availability and information
"""
try:
result = await self.update_manager.check_for_updates()
return PM3ServiceResult(
success=True,
data=result
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="update_check_error",
message="Failed to check for updates",
details=str(e)
)
)
async def download_update(self) -> PM3ServiceResult:
"""Download the latest available update.
Returns:
PM3ServiceResult indicating download success/failure
"""
try:
success = await self.update_manager.download_update()
if success:
return PM3ServiceResult(
success=True,
data={
"message": "Update downloaded successfully",
"ready_to_install": True
}
)
else:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="download_failed",
message="Update download failed"
)
)
except ValueError as e:
# No update available
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="no_update_available",
message=str(e)
)
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="update_download_error",
message="Error downloading update",
details=str(e)
)
)
async def install_update(self) -> PM3ServiceResult:
"""Install the downloaded update.
Returns:
PM3ServiceResult indicating installation success/failure
"""
try:
success = await self.update_manager.install_update()
if success:
return PM3ServiceResult(
success=True,
data={
"message": "Update installed successfully",
"requires_restart": True
}
)
else:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="installation_failed",
message="Update installation failed"
)
)
except ValueError as e:
# No update downloaded
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="no_update_downloaded",
message=str(e)
)
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="update_install_error",
message="Error installing update",
details=str(e)
)
)
async def get_progress(self) -> PM3ServiceResult:
"""Get current update progress.
Returns:
PM3ServiceResult with progress information
"""
try:
progress = await self.update_manager.get_progress()
return PM3ServiceResult(
success=True,
data={
"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
}
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="progress_error",
message="Failed to get update progress",
details=str(e)
)
)
async def get_release_notes(
self,
version: Optional[str] = None
) -> PM3ServiceResult:
"""Get release notes for a specific version or latest.
Args:
version: Version to get notes for (latest if None)
Returns:
PM3ServiceResult with release notes
"""
try:
notes = await self.update_manager.get_release_notes(version)
return PM3ServiceResult(
success=True,
data={
"version": version or "latest",
"release_notes": notes
}
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="release_notes_error",
message="Failed to get release notes",
details=str(e)
)
)
async def check_and_download_update(self) -> PM3ServiceResult:
"""Combined operation: check for updates and download if available.
Returns:
PM3ServiceResult with check and download status
"""
try:
# First check for updates
check_result = await self.check_for_updates()
if not check_result.success:
return check_result
# If update available, download it
if check_result.data.get("update_available"):
download_result = await self.download_update()
if download_result.success:
return PM3ServiceResult(
success=True,
data={
"message": "Update checked and downloaded",
"update_info": check_result.data,
"ready_to_install": True
}
)
else:
return download_result
else:
return PM3ServiceResult(
success=True,
data={
"message": "System is up to date",
"update_available": False,
"current_version": check_result.data.get("current_version")
}
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="check_download_error",
message="Error checking and downloading update",
details=str(e)
)
)
async def full_update(self) -> PM3ServiceResult:
"""Full update workflow: check, download, and install.
Returns:
PM3ServiceResult with complete update status
"""
try:
# Check for updates
check_result = await self.check_for_updates()
if not check_result.success:
return check_result
if not check_result.data.get("update_available"):
return PM3ServiceResult(
success=True,
data={
"message": "System is already up to date",
"update_performed": False
}
)
# Download update
download_result = await self.download_update()
if not download_result.success:
return download_result
# Install update
install_result = await self.install_update()
if not install_result.success:
return install_result
return PM3ServiceResult(
success=True,
data={
"message": "Update completed successfully",
"update_performed": True,
"previous_version": check_result.data.get("current_version"),
"new_version": check_result.data.get("latest_version"),
"requires_restart": True
}
)
except Exception as e:
return PM3ServiceResult(
success=False,
error=PM3ServiceError(
code="full_update_error",
message="Error performing full update",
details=str(e)
)
)