simple event bus impl
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
from .bus import EventBus, EventSubscriber, InMemoryEventSink
|
||||
from .models import McpEvent, make_event
|
||||
|
||||
__all__ = [
|
||||
"EventBus",
|
||||
"EventSubscriber",
|
||||
"InMemoryEventSink",
|
||||
"McpEvent",
|
||||
"make_event",
|
||||
]
|
||||
@@ -0,0 +1,44 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
from .models import McpEvent
|
||||
|
||||
EventSubscriber = Callable[[McpEvent], None]
|
||||
|
||||
|
||||
class InMemoryEventSink:
|
||||
"""Append-only event sink used by current broker history APIs."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._events: list[McpEvent] = []
|
||||
|
||||
def __call__(self, event: McpEvent) -> None:
|
||||
self._events.append(event)
|
||||
|
||||
def list_events(self) -> list[McpEvent]:
|
||||
"""Return a defensive copy of recorded events."""
|
||||
return list(self._events)
|
||||
|
||||
|
||||
class EventBus:
|
||||
"""Synchronous in-process fanout for broker-local events.
|
||||
|
||||
This is intentionally not an MCP notification system. Protocol projections
|
||||
can subscribe later without changing service code that emits events.
|
||||
"""
|
||||
|
||||
def __init__(self, history: InMemoryEventSink | None = None) -> None:
|
||||
self._history = history or InMemoryEventSink()
|
||||
self._subscribers: list[EventSubscriber] = [self._history]
|
||||
|
||||
def subscribe(self, subscriber: EventSubscriber) -> None:
|
||||
self._subscribers.append(subscriber)
|
||||
|
||||
def publish(self, event: McpEvent) -> None:
|
||||
for subscriber in self._subscribers:
|
||||
subscriber(event)
|
||||
|
||||
def list_events(self) -> list[McpEvent]:
|
||||
"""Expose the default history sink for compatibility tools/resources."""
|
||||
return self._history.list_events()
|
||||
@@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class McpEvent:
|
||||
"""Broker-local event record before protocol-specific projection."""
|
||||
|
||||
kind: str
|
||||
timestamp_epoch_ms: int
|
||||
connection_id: str | None = None
|
||||
capability_id: str | None = None
|
||||
workflow_name: str | None = None
|
||||
payload: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
def make_event(
|
||||
kind: str,
|
||||
*,
|
||||
connection_id: str | None = None,
|
||||
capability_id: str | None = None,
|
||||
workflow_name: str | None = None,
|
||||
payload: dict[str, Any] | None = None,
|
||||
) -> McpEvent:
|
||||
"""Create a timestamped event with optional routing metadata."""
|
||||
return McpEvent(
|
||||
kind=kind,
|
||||
timestamp_epoch_ms=int(time.time() * 1000),
|
||||
connection_id=connection_id,
|
||||
capability_id=capability_id,
|
||||
workflow_name=workflow_name,
|
||||
payload=payload or {},
|
||||
)
|
||||
Reference in New Issue
Block a user