Skip to main content

swink_agent/agent/
events.rs

1use std::sync::Arc;
2
3use tracing::warn;
4
5use crate::loop_::AgentEvent;
6
7use super::{Agent, SubscriptionId};
8
9impl Agent {
10    /// Subscribe to agent events. Returns a subscription ID for later removal.
11    pub fn subscribe(
12        &mut self,
13        callback: impl Fn(&AgentEvent) + Send + Sync + 'static,
14    ) -> SubscriptionId {
15        self.listeners.subscribe(callback)
16    }
17
18    /// Remove a subscription. Returns `true` if the subscription existed.
19    pub fn unsubscribe(&mut self, id: SubscriptionId) -> bool {
20        self.listeners.unsubscribe(id)
21    }
22
23    /// Dispatch an event to all listeners, catching panics.
24    ///
25    /// Any listener that panics is automatically unsubscribed.
26    pub(super) fn dispatch_event(&mut self, event: &AgentEvent) {
27        self.listeners.dispatch(event);
28
29        for forwarder in &self.event_forwarders {
30            let guarded = std::panic::AssertUnwindSafe(|| forwarder(event.clone()));
31            if let Err(error) = std::panic::catch_unwind(guarded) {
32                warn!("event forwarder panicked: {error:?}");
33            }
34        }
35    }
36
37    /// Add an event forwarder at runtime.
38    pub fn add_event_forwarder(&mut self, f: impl Fn(AgentEvent) + Send + Sync + 'static) {
39        self.event_forwarders.push(Arc::new(f));
40    }
41
42    /// Dispatch an external event to all listeners and forwarders.
43    ///
44    /// Used for cross-agent event forwarding.
45    pub fn forward_event(&mut self, event: &AgentEvent) {
46        self.dispatch_event(event);
47    }
48
49    /// Emit a custom named event to all subscribers and forwarders.
50    pub fn emit(&mut self, name: impl Into<String>, payload: serde_json::Value) {
51        let event = AgentEvent::Custom(crate::emit::Emission::new(name, payload));
52        self.dispatch_event(&event);
53    }
54}