bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
151 lines
4.7 KiB
Python
151 lines
4.7 KiB
Python
"""
|
|
Event Bus for async communication between services
|
|
"""
|
|
|
|
from typing import Dict, List, Callable, Any
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
import asyncio
|
|
import json
|
|
|
|
|
|
class EventType(str, Enum):
|
|
"""Event types"""
|
|
OBSERVATION_CREATED = "observation.created"
|
|
OBSERVATION_UPDATED = "observation.updated"
|
|
SIGNAL_GENERATED = "signal.generated"
|
|
DECISION_MADE = "decision.made"
|
|
OUTCOME_RECORDED = "outcome.recorded"
|
|
INTERVENTION_STARTED = "intervention.started"
|
|
INTERVENTION_COMPLETED = "intervention.completed"
|
|
MODEL_UPDATED = "model.updated"
|
|
PLATFORM_CHANGE = "platform.change"
|
|
SYNC_COMPLETED = "sync.completed"
|
|
ALERT_TRIGGERED = "alert.triggered"
|
|
|
|
|
|
@dataclass
|
|
class Event:
|
|
"""Platform event"""
|
|
event_id: str
|
|
event_type: EventType
|
|
payload: Dict[str, Any]
|
|
timestamp: str
|
|
source: str
|
|
correlation_id: Optional[str] = None
|
|
|
|
def to_dict(self) -> Dict:
|
|
return {
|
|
"event_id": self.event_id,
|
|
"event_type": self.event_type.value,
|
|
"payload": self.payload,
|
|
"timestamp": self.timestamp,
|
|
"source": self.source,
|
|
"correlation_id": self.correlation_id
|
|
}
|
|
|
|
|
|
class EventBus:
|
|
"""Event bus for async communication"""
|
|
|
|
def __init__(self):
|
|
self.subscribers: Dict[EventType, List[Callable]] = {}
|
|
self.event_history: List[Event] = []
|
|
self.max_history = 10000
|
|
|
|
def subscribe(self, event_type: EventType, handler: Callable):
|
|
"""Subscribe to an event type"""
|
|
if event_type not in self.subscribers:
|
|
self.subscribers[event_type] = []
|
|
self.subscribers[event_type].append(handler)
|
|
|
|
def unsubscribe(self, event_type: EventType, handler: Callable):
|
|
"""Unsubscribe from an event type"""
|
|
if event_type in self.subscribers:
|
|
if handler in self.subscribers[event_type]:
|
|
self.subscribers[event_type].remove(handler)
|
|
|
|
async def publish(self, event: Event):
|
|
"""Publish an event"""
|
|
# Store in history
|
|
self.event_history.append(event)
|
|
if len(self.event_history) > self.max_history:
|
|
self.event_history = self.event_history[-self.max_history:]
|
|
|
|
# Notify subscribers
|
|
handlers = self.subscribers.get(event.event_type, [])
|
|
|
|
# Run handlers concurrently
|
|
if handlers:
|
|
await asyncio.gather(
|
|
*[self._run_handler(handler, event) for handler in handlers],
|
|
return_exceptions=True
|
|
)
|
|
|
|
async def _run_handler(self, handler: Callable, event: Event):
|
|
"""Run a handler with error handling"""
|
|
try:
|
|
if asyncio.iscoroutinefunction(handler):
|
|
await handler(event)
|
|
else:
|
|
handler(event)
|
|
except Exception as e:
|
|
print(f"Event handler error: {e}")
|
|
|
|
def get_events(self, event_type: Optional[EventType] = None, limit: int = 100) -> List[Dict]:
|
|
"""Get recent events"""
|
|
events = self.event_history
|
|
|
|
if event_type:
|
|
events = [e for e in events if e.event_type == event_type]
|
|
|
|
return [e.to_dict() for e in events[-limit:]]
|
|
|
|
def get_stats(self) -> Dict:
|
|
"""Get event bus statistics"""
|
|
return {
|
|
"total_events": len(self.event_history),
|
|
"subscribers": {
|
|
event_type.value: len(handlers)
|
|
for event_type, handlers in self.subscribers.items()
|
|
},
|
|
"event_types": list(set(e.event_type.value for e in self.event_history))
|
|
}
|
|
|
|
|
|
# Global event bus
|
|
event_bus = EventBus()
|
|
|
|
|
|
# Example event handlers
|
|
async def on_observation_created(event: Event):
|
|
"""Handle observation created event"""
|
|
print(f"New observation: {event.payload.get('observation_id')}")
|
|
# Trigger signal generation
|
|
# Trigger sync to targets
|
|
# Update global model
|
|
|
|
|
|
async def on_decision_made(event: Event):
|
|
"""Handle decision made event"""
|
|
print(f"New decision: {event.payload.get('decision_type')}")
|
|
# Notify stakeholders
|
|
# Update decision knowledge
|
|
# Trigger autonomous actions if enabled
|
|
|
|
|
|
async def on_outcome_recorded(event: Event):
|
|
"""Handle outcome recorded event"""
|
|
print(f"New outcome: {event.payload.get('intervention_id')}")
|
|
# Update evidence engine
|
|
# Update global model
|
|
# Generate insights
|
|
# Broadcast to connected clients
|
|
|
|
|
|
# Register handlers
|
|
event_bus.subscribe(EventType.OBSERVATION_CREATED, on_observation_created)
|
|
event_bus.subscribe(EventType.DECISION_MADE, on_decision_made)
|
|
event_bus.subscribe(EventType.OUTCOME_RECORDED, on_outcome_recorded)
|