33#include <unordered_map>
87 static const size_t type_id = std::hash<std::type_index>{}(std::type_index(
typeid(T)));
94 using detail::event_type_id;
116 event(
const std::string& type,
const std::string& data =
"")
163 uint64_t handler_id)>;
173 template<concepts::EventType EventType>
178 std::vector<subscription_info> snapshot;
181 std::lock_guard<std::mutex> lock(
mutex_);
183 auto range =
handlers_.equal_range(type_id);
184 snapshot.reserve(std::distance(range.first, range.second));
185 for (
auto it = range.first; it != range.second; ++it) {
186 snapshot.push_back(it->second);
195 for (
auto& entry : snapshot) {
198 if (entry.expected_type_id != type_id) {
200 error_cb(
"Type ID mismatch detected in event handler",
207 entry.handler(
static_cast<const void*
>(&evt));
209 }
catch (
const std::exception& e) {
211 std::string error_msg =
"Exception in event handler: ";
212 error_msg += e.what();
213 error_cb(error_msg, type_id, entry.id);
217 error_cb(
"Unknown exception in event handler",
227 std::vector<subscription_info> snapshot;
230 std::lock_guard<std::mutex> lock(
mutex_);
232 auto range =
handlers_.equal_range(type_id);
233 snapshot.reserve(std::distance(range.first, range.second));
234 for (
auto it = range.first; it != range.second; ++it) {
235 snapshot.push_back(it->second);
243 for (
auto& entry : snapshot) {
245 if (entry.expected_type_id != type_id) {
247 error_cb(
"Type ID mismatch detected in event handler",
254 entry.handler(
static_cast<const void*
>(&evt));
256 }
catch (
const std::exception& e) {
258 std::string error_msg =
"Exception in event handler: ";
259 error_msg += e.what();
260 error_cb(error_msg, type_id, entry.id);
264 error_cb(
"Unknown exception in event handler",
280 template<concepts::EventType EventType, concepts::EventHandler<EventType> HandlerFunc>
282 std::lock_guard<std::mutex> lock(
mutex_);
289 info.expected_type_id = type_id;
291 info.handler = [f = std::function<void(const EventType&)>(std::forward<HandlerFunc>(func))]
292 (
const void* evt_ptr) {
293 f(*
static_cast<const EventType*
>(evt_ptr));
296 handlers_.emplace(type_id, std::move(info));
303 std::lock_guard<std::mutex> lock(
mutex_);
310 info.expected_type_id = type_id;
311 info.handler = [f = std::move(func)](
const void* evt_ptr) {
312 f(*
static_cast<const event*
>(evt_ptr));
315 handlers_.emplace(type_id, std::move(info));
339 auto wrapped_handler = [f = std::forward<HandlerFunc>(func),
340 flt = std::forward<FilterFunc>(filter)]
341 (
const EventType& evt) {
354 std::function<
void(
const event&)>&& func,
355 std::function<
bool(
const event&)>&& filter) {
357 auto wrapped_handler = [f = std::move(func),
358 flt = std::move(filter)]
366 return subscribe(std::move(wrapped_handler));
370 std::lock_guard<std::mutex> lock(
mutex_);
374 if (it->second.id ==
id) {
408 std::lock_guard<std::mutex> lock(
mutex_);
416 std::lock_guard<std::mutex> lock(
mutex_);
437 std::unordered_multimap<size_t, subscription_info>
handlers_;
512 timestamp(std::chrono::steady_clock::now()) {}
525 timestamp(std::chrono::steady_clock::now()) {}
538 error_event(
const std::string& module,
const std::string& message,
int code)
540 timestamp(std::chrono::steady_clock::now()) {}
553 metric_event(
const std::string& n,
double v,
const std::string& u =
"")
555 timestamp(std::chrono::steady_clock::now()) {}
Simple synchronous event bus for testing when monitoring is disabled.
std::function< void(const std::string &error_message, size_t event_type_id, uint64_t handler_id)> error_callback_t
Type for error callback function.
std::unordered_multimap< size_t, subscription_info > handlers_
void set_error_callback(error_callback_t callback)
Set the error callback for handler exceptions and type mismatches.
error_callback_t error_callback_
void unsubscribe(uint64_t id)
void clear_error_callback()
Clear the error callback.
uint64_t subscribe_filtered(HandlerFunc &&func, FilterFunc &&filter)
Subscribe to events with a filter function.
void publish(event &&evt, event_priority=event_priority::normal)
uint64_t subscribe_filtered(std::function< void(const event &)> &&func, std::function< bool(const event &)> &&filter)
std::atomic< bool > running_
uint64_t subscribe(HandlerFunc &&func)
Subscribe to events of a specific type.
std::atomic< uint64_t > next_id_
uint64_t subscribe(std::function< void(const event &)> &&func)
static simple_event_bus & instance()
Get the singleton instance (thread-safe via C++11 magic statics)
void publish(const EventType &evt, event_priority=event_priority::normal)
Publish an event to all subscribed handlers.
A callable that filters events based on criteria.
A callable that can handle events of a specific type.
A type that can be used as an event in the event bus.
C++20 concepts for event bus types.
constexpr int event_bus_abi_version
constexpr int get_event_bus_abi_version()
Get the ABI version of the event_bus implementation.
simple_event_bus & get_event_bus()
Access the global event bus instance.
uint64_t subscription_id
Type alias for subscription ID.
std::function< void(const T &)> event_handler
bool verify_event_bus_abi(int expected_version)
Verify ABI compatibility between modules.
Generate unique type ID for each event type using std::type_index.
Generic event structure for the event bus.
std::string get_type() const
std::string get_data() const
void set_type(const std::string &type)
void set_data(const std::string &data)
event(const std::string &type, const std::string &data="")
Event published when an error occurs.
std::chrono::steady_clock::time_point timestamp
std::string error_message
error_event(const std::string &module, const std::string &message, int code)
Event for publishing metrics.
metric_event(const std::string &n, double v, const std::string &u="")
std::chrono::steady_clock::time_point timestamp
Event published when a module starts.
module_started_event(const std::string &name)
std::chrono::steady_clock::time_point timestamp
Event published when a module stops.
module_stopped_event(const std::string &name)
std::chrono::steady_clock::time_point timestamp
std::function< void(const void *)> handler