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:
192
app/backend/services/container.py
Normal file
192
app/backend/services/container.py
Normal file
@@ -0,0 +1,192 @@
|
||||
"""Service Container for Dependency Injection.
|
||||
|
||||
This module provides a singleton container that manages service instances
|
||||
and their dependencies, ensuring consistent state across all interfaces
|
||||
(REST API, BLE GATT, plugins, etc.).
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from ..workers.pm3_worker import PM3Worker, SubprocessPM3Worker
|
||||
from ..managers.session_manager import SessionManager
|
||||
from ..managers.wifi_manager import WiFiManager
|
||||
from ..managers.update_manager import get_update_manager
|
||||
from ..managers.pm3_device_manager import PM3DeviceManager
|
||||
|
||||
from .pm3_service import PM3Service
|
||||
from .system_service import SystemService
|
||||
from .wifi_service import WiFiService
|
||||
from .update_service import UpdateService
|
||||
|
||||
|
||||
class ServiceContainer:
|
||||
"""Dependency injection container for services.
|
||||
|
||||
This container:
|
||||
- Creates and manages singleton instances of services
|
||||
- Injects shared dependencies (workers, managers)
|
||||
- Ensures consistent state across all interfaces
|
||||
- Provides centralized access to services
|
||||
|
||||
Usage:
|
||||
# In REST API
|
||||
from app.backend.services.container import container
|
||||
result = await container.pm3_service.execute_command(...)
|
||||
|
||||
# In BLE GATT
|
||||
from app.backend.services.container import container
|
||||
result = await container.pm3_service.execute_command(...)
|
||||
|
||||
# Both use the same service instance!
|
||||
"""
|
||||
|
||||
_instance: Optional['ServiceContainer'] = None
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize service container with shared dependencies."""
|
||||
if ServiceContainer._instance is not None:
|
||||
raise RuntimeError(
|
||||
"ServiceContainer is a singleton. Use container.get_instance() "
|
||||
"or import the global 'container' instance."
|
||||
)
|
||||
|
||||
# Create shared worker/manager instances
|
||||
# These are the low-level components that services will use
|
||||
# Use PM3Worker with SWIG bindings for better performance
|
||||
# Falls back to SubprocessPM3Worker if SWIG import fails
|
||||
try:
|
||||
self._pm3_worker = PM3Worker() # Try SWIG bindings first
|
||||
except Exception:
|
||||
self._pm3_worker = SubprocessPM3Worker() # Fallback to subprocess
|
||||
self._pm3_device_manager = PM3DeviceManager() # NEW: Multi-device manager
|
||||
self._session_manager = SessionManager()
|
||||
self._wifi_manager = WiFiManager()
|
||||
self._update_manager = get_update_manager()
|
||||
|
||||
# Create service instances with injected dependencies
|
||||
self._pm3_service = PM3Service(
|
||||
pm3_worker=self._pm3_worker,
|
||||
session_manager=self._session_manager,
|
||||
device_manager=self._pm3_device_manager # NEW: Multi-device support
|
||||
)
|
||||
|
||||
self._system_service = SystemService()
|
||||
|
||||
self._wifi_service = WiFiService(
|
||||
wifi_manager=self._wifi_manager
|
||||
)
|
||||
|
||||
self._update_service = UpdateService(
|
||||
update_manager=self._update_manager
|
||||
)
|
||||
|
||||
# Note: WorkflowService will be added in Phase 5
|
||||
# self._workflow_service = WorkflowService(
|
||||
# pm3_service=self._pm3_service
|
||||
# )
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls) -> 'ServiceContainer':
|
||||
"""Get the singleton service container instance.
|
||||
|
||||
Returns:
|
||||
ServiceContainer instance
|
||||
"""
|
||||
if cls._instance is None:
|
||||
cls._instance = ServiceContainer()
|
||||
return cls._instance
|
||||
|
||||
@classmethod
|
||||
def reset_instance(cls):
|
||||
"""Reset the singleton instance.
|
||||
|
||||
This is primarily used for testing purposes.
|
||||
"""
|
||||
cls._instance = None
|
||||
|
||||
# Service properties (read-only access)
|
||||
|
||||
@property
|
||||
def pm3_service(self) -> PM3Service:
|
||||
"""Get PM3 service instance.
|
||||
|
||||
Returns:
|
||||
Shared PM3Service instance
|
||||
"""
|
||||
return self._pm3_service
|
||||
|
||||
@property
|
||||
def system_service(self) -> SystemService:
|
||||
"""Get system service instance.
|
||||
|
||||
Returns:
|
||||
Shared SystemService instance
|
||||
"""
|
||||
return self._system_service
|
||||
|
||||
@property
|
||||
def wifi_service(self) -> WiFiService:
|
||||
"""Get WiFi service instance.
|
||||
|
||||
Returns:
|
||||
Shared WiFiService instance
|
||||
"""
|
||||
return self._wifi_service
|
||||
|
||||
@property
|
||||
def update_service(self) -> UpdateService:
|
||||
"""Get update service instance.
|
||||
|
||||
Returns:
|
||||
Shared UpdateService instance
|
||||
"""
|
||||
return self._update_service
|
||||
|
||||
# Manager/Worker access (for cases where direct access is needed)
|
||||
|
||||
@property
|
||||
def pm3_worker(self) -> PM3Worker:
|
||||
"""Get PM3 worker instance.
|
||||
|
||||
Returns:
|
||||
Shared PM3Worker instance
|
||||
"""
|
||||
return self._pm3_worker
|
||||
|
||||
@property
|
||||
def session_manager(self) -> SessionManager:
|
||||
"""Get session manager instance.
|
||||
|
||||
Returns:
|
||||
Shared SessionManager instance
|
||||
"""
|
||||
return self._session_manager
|
||||
|
||||
@property
|
||||
def wifi_manager(self) -> WiFiManager:
|
||||
"""Get WiFi manager instance.
|
||||
|
||||
Returns:
|
||||
Shared WiFiManager instance
|
||||
"""
|
||||
return self._wifi_manager
|
||||
|
||||
@property
|
||||
def pm3_device_manager(self) -> PM3DeviceManager:
|
||||
"""Get PM3 device manager instance.
|
||||
|
||||
Returns:
|
||||
Shared PM3DeviceManager instance for multi-device support
|
||||
"""
|
||||
return self._pm3_device_manager
|
||||
|
||||
|
||||
# Global singleton instance
|
||||
# Import this throughout the codebase for consistent service access
|
||||
container = ServiceContainer.get_instance()
|
||||
|
||||
|
||||
# Convenience exports for common services
|
||||
__all__ = [
|
||||
'ServiceContainer',
|
||||
'container',
|
||||
]
|
||||
Reference in New Issue
Block a user