Define governed platform event envelope
This commit is contained in:
@@ -7,7 +7,7 @@ from contextvars import ContextVar
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
import re
|
||||
from typing import Any
|
||||
from typing import Any, Literal
|
||||
import uuid
|
||||
|
||||
|
||||
@@ -31,6 +31,39 @@ class EventTrace:
|
||||
causation_id: str | None = None
|
||||
|
||||
|
||||
EventClassification = Literal["public", "internal", "confidential", "restricted"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class EventActorRef:
|
||||
type: str
|
||||
id: str | None = None
|
||||
label: str | None = None
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return _compact_dict({"type": self.type, "id": self.id, "label": self.label})
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class EventTenantRef:
|
||||
id: str
|
||||
slug: str | None = None
|
||||
label: str | None = None
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return _compact_dict({"id": self.id, "slug": self.slug, "label": self.label})
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class EventObjectRef:
|
||||
type: str
|
||||
id: str | None = None
|
||||
label: str | None = None
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return _compact_dict({"type": self.type, "id": self.id, "label": self.label})
|
||||
|
||||
|
||||
_current_trace: ContextVar[EventTrace | None] = ContextVar("govoplan_event_trace", default=None)
|
||||
|
||||
|
||||
@@ -43,6 +76,27 @@ class PlatformEvent:
|
||||
event_id: str = field(default_factory=new_event_id)
|
||||
correlation_id: str | None = None
|
||||
causation_id: str | None = None
|
||||
actor: EventActorRef | None = None
|
||||
tenant: EventTenantRef | None = None
|
||||
subject: EventObjectRef | None = None
|
||||
resource: EventObjectRef | None = None
|
||||
classification: EventClassification = "internal"
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"type": self.type,
|
||||
"module_id": self.module_id,
|
||||
"payload": dict(self.payload),
|
||||
"occurred_at": self.occurred_at.isoformat(),
|
||||
"event_id": self.event_id,
|
||||
"correlation_id": self.correlation_id,
|
||||
"causation_id": self.causation_id,
|
||||
"actor": self.actor.to_dict() if self.actor else None,
|
||||
"tenant": self.tenant.to_dict() if self.tenant else None,
|
||||
"subject": self.subject.to_dict() if self.subject else None,
|
||||
"resource": self.resource.to_dict() if self.resource else None,
|
||||
"classification": self.classification,
|
||||
}
|
||||
|
||||
|
||||
EventHandler = Callable[[PlatformEvent], None]
|
||||
@@ -90,6 +144,11 @@ def ensure_event_trace(event: PlatformEvent) -> PlatformEvent:
|
||||
event_id=event.event_id,
|
||||
correlation_id=trace.correlation_id,
|
||||
causation_id=trace.causation_id,
|
||||
actor=event.actor,
|
||||
tenant=event.tenant,
|
||||
subject=event.subject,
|
||||
resource=event.resource,
|
||||
classification=event.classification,
|
||||
)
|
||||
|
||||
|
||||
@@ -107,3 +166,7 @@ class EventBus:
|
||||
handler(traced)
|
||||
for handler in self._subscribers.get("*", ()):
|
||||
handler(traced)
|
||||
|
||||
|
||||
def _compact_dict(value: Mapping[str, Any]) -> dict[str, Any]:
|
||||
return {key: item for key, item in value.items() if item is not None}
|
||||
|
||||
Reference in New Issue
Block a user