SkyOSFullCore / modules /sync /sync_manager.py
sky-meilin's picture
Create sync_manager.py
c26996b verified
Raw History Blame
7.15 kB
"""
SkyOS Sync Manager.
Central orchestration layer for the synchronization subsystem.
The SyncManager coordinates:
- adapter registration and lookup
- scheduled synchronization
- structured logging
- conflict resolution
Actual data transport remains the responsibility of adapters.
"""
from __future__ import annotations
from typing import Any, Dict, Iterable, List, Optional
from .conflict_resolver import ConflictResolver
from .logger import SyncLogger
from .registry import AdapterRegistry
from .scheduler import SyncScheduler
class SyncManager:
"""
Central coordinator for the SkyOS synchronization layer.
The manager does not directly implement provider-specific synchronization.
Instead, it coordinates registered adapters and the surrounding sync
infrastructure.
"""
def __init__(
self,
registry: Optional[AdapterRegistry] = None,
scheduler: Optional[SyncScheduler] = None,
logger: Optional[SyncLogger] = None,
conflict_resolver: Optional[ConflictResolver] = None,
) -> None:
self.registry = registry or AdapterRegistry()
self.scheduler = scheduler or SyncScheduler()
self.logger = logger or SyncLogger()
self.conflict_resolver = (
conflict_resolver or ConflictResolver()
)
self._initialized = False
def initialize(self) -> None:
"""
Initialize the synchronization manager.
Initialization is intentionally idempotent so the manager can safely
be initialized by application startup code more than once.
"""
if self._initialized:
return
self._initialized = True
self.logger.info(
"SyncManager initialized",
component="sync_manager",
)
def register_adapter(
self,
name: str,
adapter: Any,
) -> Any:
"""
Register an adapter with the central registry.
Args:
name: Logical adapter name.
adapter: Adapter instance.
Returns:
The registered adapter.
"""
registered_adapter = self.registry.register(name, adapter)
self.logger.info(
"Sync adapter registered",
adapter=name,
component="sync_manager",
)
return registered_adapter
def get_adapter(self, name: str) -> Any:
"""
Retrieve a registered adapter.
Args:
name: Logical adapter name.
Returns:
Registered adapter instance.
"""
return self.registry.get(name)
def list_adapters(self) -> List[str]:
"""
Return the names of all registered adapters.
"""
return list(self.registry.list())
def resolve_conflict(
self,
local_data: Any,
remote_data: Any,
context: Optional[Dict[str, Any]] = None,
) -> Any:
"""
Delegate conflict resolution to the ConflictResolver.
"""
return self.conflict_resolver.resolve(
local_data=local_data,
remote_data=remote_data,
context=context or {},
)
def schedule(
self,
name: str,
callback: Any,
*args: Any,
**kwargs: Any,
) -> Any:
"""
Register a synchronization task with the scheduler.
"""
self.logger.info(
"Synchronization task scheduled",
task=name,
component="sync_manager",
)
return self.scheduler.schedule(
name,
callback,
*args,
**kwargs,
)
def run_adapter(
self,
adapter_name: str,
*args: Any,
**kwargs: Any,
) -> Any:
"""
Execute a registered adapter.
The SyncManager intentionally performs only orchestration here.
Provider-specific behavior remains inside the adapter.
"""
adapter = self.get_adapter(adapter_name)
self.logger.info(
"Executing sync adapter",
adapter=adapter_name,
component="sync_manager",
)
if hasattr(adapter, "sync"):
return adapter.sync(*args, **kwargs)
if hasattr(adapter, "run"):
return adapter.run(*args, **kwargs)
raise AttributeError(
f"Adapter '{adapter_name}' does not provide "
"'sync' or 'run'."
)
def sync(
self,
source: str,
target: str,
*args: Any,
**kwargs: Any,
) -> Any:
"""
Orchestrate a synchronization between two registered adapters.
This method provides the central flow:
source adapter
↓
SyncManager
↓
conflict resolution
↓
target adapter
Provider-specific data handling remains delegated to the adapters.
"""
self.initialize()
source_adapter = self.get_adapter(source)
target_adapter = self.get_adapter(target)
self.logger.info(
"Synchronization started",
source=source,
target=target,
component="sync_manager",
)
if hasattr(source_adapter, "export"):
data = source_adapter.export(*args, **kwargs)
elif hasattr(source_adapter, "read"):
data = source_adapter.read(*args, **kwargs)
elif hasattr(source_adapter, "sync"):
data = source_adapter.sync(*args, **kwargs)
else:
raise AttributeError(
f"Source adapter '{source}' does not provide "
"'export', 'read', or 'sync'."
)
if hasattr(target_adapter, "import_data"):
result = target_adapter.import_data(data)
elif hasattr(target_adapter, "write"):
result = target_adapter.write(data)
elif hasattr(target_adapter, "push"):
result = target_adapter.push(data)
else:
raise AttributeError(
f"Target adapter '{target}' does not provide "
"'import_data', 'write', or 'push'."
)
self.logger.info(
"Synchronization completed",
source=source,
target=target,
component="sync_manager",
)
return result
def status(self) -> Dict[str, Any]:
"""
Return the current state of the synchronization manager.
"""
return {
"initialized": self._initialized,
"adapters": self.list_adapters(),
"scheduler": self.scheduler,
"conflict_resolver": self.conflict_resolver,
}
def shutdown(self) -> None:
"""
Shut down the synchronization layer cleanly.
"""
self.logger.info(
"SyncManager shutting down",
component="sync_manager",
)
if hasattr(self.scheduler, "shutdown"):
self.scheduler.shutdown()
self._initialized = False