remove infra.md.example, infra.md is the source of truth
This commit is contained in:
119
ayn-antivirus/ayn_antivirus/core/event_bus.py
Normal file
119
ayn-antivirus/ayn_antivirus/core/event_bus.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""Simple publish/subscribe event bus for AYN Antivirus.
|
||||
|
||||
Decouples the scan engine from consumers like the CLI, logger, quarantine
|
||||
manager, and real-time monitor so each component can react to events
|
||||
independently.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import threading
|
||||
from enum import Enum, auto
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Event types
|
||||
# ---------------------------------------------------------------------------
|
||||
class EventType(Enum):
|
||||
"""All events emitted by the AYN engine."""
|
||||
|
||||
THREAT_FOUND = auto()
|
||||
SCAN_STARTED = auto()
|
||||
SCAN_COMPLETED = auto()
|
||||
FILE_SCANNED = auto()
|
||||
SIGNATURE_UPDATED = auto()
|
||||
QUARANTINE_ACTION = auto()
|
||||
REMEDIATION_ACTION = auto()
|
||||
DASHBOARD_METRIC = auto()
|
||||
|
||||
|
||||
# Type alias for subscriber callbacks.
|
||||
Callback = Callable[[EventType, Any], None]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# EventBus
|
||||
# ---------------------------------------------------------------------------
|
||||
class EventBus:
|
||||
"""Thread-safe publish/subscribe event bus.
|
||||
|
||||
Usage::
|
||||
|
||||
bus = EventBus()
|
||||
bus.subscribe(EventType.THREAT_FOUND, lambda et, data: print(data))
|
||||
bus.publish(EventType.THREAT_FOUND, {"path": "/tmp/evil.elf"})
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._subscribers: Dict[EventType, List[Callback]] = {et: [] for et in EventType}
|
||||
self._lock = threading.Lock()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Public API
|
||||
# ------------------------------------------------------------------
|
||||
def subscribe(self, event_type: EventType, callback: Callback) -> None:
|
||||
"""Register *callback* to be invoked whenever *event_type* is published.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event_type:
|
||||
The event to listen for.
|
||||
callback:
|
||||
A callable with signature ``(event_type, data) -> None``.
|
||||
"""
|
||||
with self._lock:
|
||||
if callback not in self._subscribers[event_type]:
|
||||
self._subscribers[event_type].append(callback)
|
||||
|
||||
def unsubscribe(self, event_type: EventType, callback: Callback) -> None:
|
||||
"""Remove a previously-registered callback."""
|
||||
with self._lock:
|
||||
try:
|
||||
self._subscribers[event_type].remove(callback)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def publish(self, event_type: EventType, data: Any = None) -> None:
|
||||
"""Emit an event, invoking all registered callbacks synchronously.
|
||||
|
||||
Exceptions raised by individual callbacks are logged and swallowed so
|
||||
that one faulty subscriber cannot break the pipeline.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event_type:
|
||||
The event being emitted.
|
||||
data:
|
||||
Arbitrary payload — typically a dataclass or dict.
|
||||
"""
|
||||
with self._lock:
|
||||
callbacks = list(self._subscribers[event_type])
|
||||
|
||||
for cb in callbacks:
|
||||
try:
|
||||
cb(event_type, data)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Subscriber %r raised an exception for event %s",
|
||||
cb,
|
||||
event_type.name,
|
||||
)
|
||||
|
||||
def clear(self, event_type: EventType | None = None) -> None:
|
||||
"""Remove all subscribers for *event_type*, or all subscribers if ``None``."""
|
||||
with self._lock:
|
||||
if event_type is None:
|
||||
for et in EventType:
|
||||
self._subscribers[et].clear()
|
||||
else:
|
||||
self._subscribers[event_type].clear()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Module-level singleton
|
||||
# ---------------------------------------------------------------------------
|
||||
event_bus = EventBus()
|
||||
Reference in New Issue
Block a user