#pragma once #include "RuntimeEventQueue.h" #include #include #include #include #include struct RuntimeEventDispatchResult { std::size_t dispatchedEvents = 0; std::size_t handlerInvocations = 0; std::size_t handlerFailures = 0; }; class RuntimeEventDispatcher { public: using Handler = std::function; explicit RuntimeEventDispatcher(std::size_t queueCapacity = 1024) : mQueue(queueCapacity) { } bool Publish(RuntimeEvent event) { if (!event.PayloadMatchesType()) return false; if (event.sequence == 0) event.sequence = mNextSequence.fetch_add(1); return mQueue.Push(std::move(event)); } template bool PublishPayload(Payload payload, std::string source = {}) { return Publish(MakeRuntimeEvent(std::move(payload), std::move(source))); } void Subscribe(RuntimeEventType type, Handler handler) { std::lock_guard lock(mHandlerMutex); mHandlers[type].push_back(std::move(handler)); } void SubscribeAll(Handler handler) { std::lock_guard lock(mHandlerMutex); mAllHandlers.push_back(std::move(handler)); } RuntimeEventDispatchResult DispatchPending(std::size_t maxEvents = 0) { RuntimeEventDispatchResult result; std::vector events = mQueue.Drain(maxEvents); result.dispatchedEvents = events.size(); for (const RuntimeEvent& event : events) { std::vector handlers = HandlersFor(event.type); result.handlerInvocations += handlers.size(); for (const Handler& handler : handlers) { try { handler(event); } catch (...) { ++result.handlerFailures; } } } return result; } bool TryPop(RuntimeEvent& event) { return mQueue.TryPop(event); } RuntimeEventQueueMetrics GetQueueMetrics(std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now()) const { return mQueue.GetMetrics(now); } std::size_t QueueDepth() const { return mQueue.Depth(); } private: std::vector HandlersFor(RuntimeEventType type) const { std::lock_guard lock(mHandlerMutex); std::vector handlers = mAllHandlers; const auto found = mHandlers.find(type); if (found != mHandlers.end()) handlers.insert(handlers.end(), found->second.begin(), found->second.end()); return handlers; } RuntimeEventQueue mQueue; std::atomic mNextSequence{ 1 }; mutable std::mutex mHandlerMutex; std::map> mHandlers; std::vector mAllHandlers; };