gateway/modules/shared/callbackRegistry.py
2025-12-15 21:55:26 +01:00

72 lines
2.6 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Callback registry for decoupled event notifications.
Allows interfaces to notify about changes without knowing about features.
Features can register callbacks to be notified when automations change.
"""
import logging
from typing import Callable, List, Dict, Any
import asyncio
logger = logging.getLogger(__name__)
class CallbackRegistry:
"""Registry for callbacks that can be triggered by interfaces without knowing about features."""
def __init__(self):
self._callbacks: Dict[str, List[Callable]] = {}
def register(self, event_type: str, callback: Callable):
"""Register a callback for a specific event type.
Args:
event_type: Type of event (e.g., 'automation.changed')
callback: Async or sync callback function
"""
if event_type not in self._callbacks:
self._callbacks[event_type] = []
self._callbacks[event_type].append(callback)
logger.debug(f"Registered callback for event type: {event_type}")
def unregister(self, event_type: str, callback: Callable):
"""Unregister a callback for a specific event type."""
if event_type in self._callbacks:
try:
self._callbacks[event_type].remove(callback)
logger.debug(f"Unregistered callback for event type: {event_type}")
except ValueError:
logger.warning(f"Callback not found for event type: {event_type}")
async def trigger(self, event_type: str, *args, **kwargs):
"""Trigger all callbacks registered for an event type.
Args:
event_type: Type of event to trigger
*args, **kwargs: Arguments to pass to callbacks
"""
if event_type not in self._callbacks:
return
callbacks = self._callbacks[event_type].copy() # Copy to avoid modification during iteration
for callback in callbacks:
try:
if asyncio.iscoroutinefunction(callback):
await callback(*args, **kwargs)
else:
callback(*args, **kwargs)
except Exception as e:
logger.error(f"Error executing callback for {event_type}: {str(e)}", exc_info=True)
def has_callbacks(self, event_type: str) -> bool:
"""Check if there are any callbacks registered for an event type."""
return event_type in self._callbacks and len(self._callbacks[event_type]) > 0
# Global singleton instance
callbackRegistry = CallbackRegistry()