use std::fmt;
use std::sync::Arc;
use std::time::Instant;
pub trait ResilienceEvent: Send + Sync + fmt::Debug {
fn event_type(&self) -> &'static str;
fn timestamp(&self) -> Instant;
fn pattern_name(&self) -> &str;
}
pub trait EventListener<E: ResilienceEvent>: Send + Sync {
fn on_event(&self, event: &E);
}
pub type BoxedEventListener<E> = Arc<dyn EventListener<E>>;
#[derive(Clone)]
pub struct EventListeners<E: ResilienceEvent> {
listeners: Vec<BoxedEventListener<E>>,
}
impl<E: ResilienceEvent> EventListeners<E> {
pub fn new() -> Self {
Self {
listeners: Vec::new(),
}
}
pub fn add<L>(&mut self, listener: L)
where
L: EventListener<E> + 'static,
{
self.listeners.push(Arc::new(listener));
}
pub fn emit(&self, event: &E) {
for listener in &self.listeners {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
listener.on_event(event);
}));
}
}
pub fn is_empty(&self) -> bool {
self.listeners.is_empty()
}
pub fn len(&self) -> usize {
self.listeners.len()
}
}
impl<E: ResilienceEvent> Default for EventListeners<E> {
fn default() -> Self {
Self::new()
}
}
pub struct FnListener<E, F>
where
F: Fn(&E) + Send + Sync,
{
f: F,
_phantom: std::marker::PhantomData<E>,
}
impl<E, F> FnListener<E, F>
where
F: Fn(&E) + Send + Sync,
{
pub fn new(f: F) -> Self {
Self {
f,
_phantom: std::marker::PhantomData,
}
}
}
impl<E, F> EventListener<E> for FnListener<E, F>
where
E: ResilienceEvent,
F: Fn(&E) + Send + Sync,
{
fn on_event(&self, event: &E) {
(self.f)(event)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
struct TestEvent {
name: String,
timestamp: Instant,
}
impl ResilienceEvent for TestEvent {
fn event_type(&self) -> &'static str {
"test"
}
fn timestamp(&self) -> Instant {
self.timestamp
}
fn pattern_name(&self) -> &str {
&self.name
}
}
#[test]
fn test_event_listeners() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = Arc::clone(&counter);
let mut listeners = EventListeners::new();
listeners.add(FnListener::new(move |_event: &TestEvent| {
counter_clone.fetch_add(1, Ordering::SeqCst);
}));
let event = TestEvent {
name: "test".to_string(),
timestamp: Instant::now(),
};
listeners.emit(&event);
assert_eq!(counter.load(Ordering::SeqCst), 1);
listeners.emit(&event);
assert_eq!(counter.load(Ordering::SeqCst), 2);
}
#[test]
fn test_multiple_listeners() {
let counter1 = Arc::new(AtomicUsize::new(0));
let counter2 = Arc::new(AtomicUsize::new(0));
let c1 = Arc::clone(&counter1);
let c2 = Arc::clone(&counter2);
let mut listeners = EventListeners::new();
listeners.add(FnListener::new(move |_: &TestEvent| {
c1.fetch_add(1, Ordering::SeqCst);
}));
listeners.add(FnListener::new(move |_: &TestEvent| {
c2.fetch_add(2, Ordering::SeqCst);
}));
let event = TestEvent {
name: "test".to_string(),
timestamp: Instant::now(),
};
listeners.emit(&event);
assert_eq!(counter1.load(Ordering::SeqCst), 1);
assert_eq!(counter2.load(Ordering::SeqCst), 2);
}
}