From cd5bd51a028d110232586fc70590e72aa7016a99 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Thu, 23 Apr 2026 19:39:36 -0500 Subject: [PATCH] Added EventBus, a simple global pub-sub event system. --- lib/cyberarm_engine.rb | 1 + lib/cyberarm_engine/event_bus.rb | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 lib/cyberarm_engine/event_bus.rb diff --git a/lib/cyberarm_engine.rb b/lib/cyberarm_engine.rb index 44c8339..1adecbf 100644 --- a/lib/cyberarm_engine.rb +++ b/lib/cyberarm_engine.rb @@ -10,6 +10,7 @@ require "json" require_relative "cyberarm_engine/version" require_relative "cyberarm_engine/stats" require_relative "cyberarm_engine/result" +require_relative "cyberarm_engine/event_bus" require_relative "cyberarm_engine/common" diff --git a/lib/cyberarm_engine/event_bus.rb b/lib/cyberarm_engine/event_bus.rb new file mode 100644 index 0000000..35768e7 --- /dev/null +++ b/lib/cyberarm_engine/event_bus.rb @@ -0,0 +1,39 @@ +module CyberarmEngine + class EventBus + Subscriber = Data.define(:event, :listener, :method, :callback) + @subscribers = [] + + def self.subscribe(event, listener = nil, method = nil, &block) + raise "Subscriber cannot have both a method AND a callback block" if method && block_given? + + subscriber = Subscriber.new(event, listener, method, block) + @subscribers << subscriber + + subscriber + end + + def self.unsubscribe(event, listener_or_subscriber) + @subscribers.delete_if { |s| s.event == event && (s == listener_or_subscriber || s.listener == listener_or_subscriber) } + end + + def self.unsubscribe!(event) + @subscribers.delete_if { |s| s.event == event } + end + + def self.announce(event, *payload) + subscribers = @subscribers.select { |s| s.event == event } + + subscribers.each do |subscriber| + subscriber&.listener&.send(subscriber.method, *payload) if subscriber&.method + subscriber.callback&.call(*payload) + rescue StandardError => e + # TODO + warn "Failed to deliver event (#{event}) to listener (#{subscriber.inspect}): #{e}" + end + end + + def self.publish(*args) + announce(*args) + end + end +end