class_name DomainEventStream extends RefCounted const SNAPSHOT_VERSION := 1 const WILDCARD_EVENT_TYPE: StringName = &"*" const RECENT_EVENT_LIMIT := 256 const MAX_BATCH_SIZE := 4_096 var _subscribers: Dictionary = {} var _published_ids: Dictionary = {} var _snapshot_ids: Array[String] = [] var _snapshot_ids_dirty := true var _recent_events: Array[SimulationDomainEvent] = [] var _pending_deliveries: Array[SimulationDomainEvent] = [] var _delivery_active := false func subscribe(event_type: StringName, subscriber_id: StringName, callback: Callable) -> bool: if event_type.is_empty() or subscriber_id.is_empty() or not callback.is_valid(): return false if not _subscribers.has(event_type): _subscribers[event_type] = {} var subscribers: Dictionary = _subscribers[event_type] if subscribers.has(subscriber_id): return false subscribers[subscriber_id] = callback return true func unsubscribe(event_type: StringName, subscriber_id: StringName) -> void: if _subscribers.has(event_type): var subscribers: Dictionary = _subscribers[event_type] subscribers.erase(subscriber_id) func publish(event: SimulationDomainEvent) -> bool: return publish_batch([event]) ## Validate and commit the entire event set before the first subscriber runs. ## Reentrant publications join the end of the delivery queue, so callbacks can ## never observe or deliver only a prefix of the committed batch. func publish_batch(events: Array) -> bool: if events.size() > MAX_BATCH_SIZE: return false var committed: Array[SimulationDomainEvent] = [] var batch_ids: Dictionary = {} for event_value: Variant in events: if not event_value is SimulationDomainEvent: return false var event: SimulationDomainEvent = event_value if event == null or not event.is_valid() \ or _published_ids.has(event.event_id) or batch_ids.has(event.event_id): return false batch_ids[event.event_id] = true committed.append(event.copy()) if not committed.is_empty(): _snapshot_ids_dirty = true for event: SimulationDomainEvent in committed: _published_ids[event.event_id] = true _recent_events.append(event.copy()) if _recent_events.size() > RECENT_EVENT_LIMIT: _recent_events.pop_front() _pending_deliveries.append(event.copy()) _drain_deliveries() return true func _drain_deliveries() -> void: if _delivery_active: return _delivery_active = true while not _pending_deliveries.is_empty(): var event: SimulationDomainEvent = _pending_deliveries.pop_front() _deliver(event) _delivery_active = false func _deliver(event: SimulationDomainEvent) -> void: var callbacks := {} _collect_callbacks(event.event_type, callbacks) _collect_callbacks(WILDCARD_EVENT_TYPE, callbacks) var subscriber_ids: Array = callbacks.keys() subscriber_ids.sort() for subscriber_id: Variant in subscriber_ids: var callback: Callable = callbacks[subscriber_id] if callback.is_valid(): callback.call(event.copy()) func has_published(event_id: StringName) -> bool: return _published_ids.has(event_id) func recent_events() -> Array[SimulationDomainEvent]: var result: Array[SimulationDomainEvent] = [] for event in _recent_events: result.append(event.copy()) return result func create_snapshot() -> Dictionary: if _snapshot_ids_dirty: _snapshot_ids.clear() for event_id: Variant in _published_ids: _snapshot_ids.append(String(event_id)) _snapshot_ids.sort() _snapshot_ids_dirty = false var saved_ids: Array[String] = _snapshot_ids.duplicate() var saved_recent: Array[Dictionary] = [] for event in _recent_events: saved_recent.append(event.to_dictionary()) return { "version": SNAPSHOT_VERSION, "published_ids": saved_ids, "recent_events": saved_recent, } func restore_snapshot(snapshot: Dictionary) -> bool: if _delivery_active or not _pending_deliveries.is_empty(): return false if int(snapshot.get("version", -1)) != SNAPSHOT_VERSION: return false if not snapshot.get("published_ids", null) is Array \ or not snapshot.get("recent_events", null) is Array: return false var restored_ids := {} for event_id: Variant in snapshot["published_ids"]: var normalized_id := StringName(event_id) if normalized_id.is_empty() or restored_ids.has(normalized_id): return false restored_ids[normalized_id] = true var restored_recent: Array[SimulationDomainEvent] = [] for event_data: Variant in snapshot["recent_events"]: if not event_data is Dictionary: return false var event := SimulationDomainEvent.from_dictionary(event_data) if not event.is_valid() or not restored_ids.has(event.event_id): return false restored_recent.append(event) if restored_recent.size() > RECENT_EVENT_LIMIT: return false _published_ids = restored_ids _snapshot_ids_dirty = true _recent_events = restored_recent _pending_deliveries.clear() return true func _collect_callbacks(event_type: StringName, target: Dictionary) -> void: if not _subscribers.has(event_type): return var source: Dictionary = _subscribers[event_type] for subscriber_id: Variant in source: if not target.has(subscriber_id): target[subscriber_id] = source[subscriber_id]