Skip to main content

consortium/
event.rs

1//! Event handler traits.
2//!
3//! Rust implementation of `ClusterShell.Event`.
4
5use std::any::Any;
6
7/// Trait for handling worker lifecycle events.
8///
9/// Implement any subset of these methods to react to events
10/// from workers and tasks. All methods have default no-op implementations.
11pub trait EventHandler: Send + Sync {
12    /// Called to indicate that a worker has just started.
13    fn ev_start(&mut self, _worker: &dyn Any) {}
14
15    /// Called for each node to indicate that a worker command for a
16    /// specific node (or key) has just started.
17    fn ev_pickup(&mut self, _worker: &dyn Any, _node: &str) {}
18
19    /// Called to indicate that a worker has data to read from a specific
20    /// node (or key).
21    fn ev_read(&mut self, _worker: &dyn Any, _node: &str, _sname: &str, _msg: &str) {}
22
23    /// Called to indicate that a worker has error to read on stderr from
24    /// a specific node (or key).
25    ///
26    /// DEPRECATED: use ev_read instead and check if sname is 'stderr'
27    fn ev_error(&mut self, _worker: &dyn Any) {}
28
29    /// Called to indicate that some writing has been done by the worker to a
30    /// node on a given stream.
31    fn ev_written(&mut self, _worker: &dyn Any, _node: &str, _sname: &str, _size: usize) {}
32
33    /// Called for each node to indicate that a worker command for a specific
34    /// node has just finished.
35    fn ev_hup(&mut self, _worker: &dyn Any, _node: &str, _rc: i32) {}
36
37    /// Called to indicate that a worker has just finished.
38    fn ev_close(&mut self, _worker: &dyn Any, _timedout: bool) {}
39
40    /// Routing event (private). Called to indicate that a (meta)worker has just
41    /// updated one of its route path.
42    fn _ev_routing(&mut self, _worker: &dyn Any, _arg: &str) {}
43
44    /// Called to indicate that a message has been received on an EnginePort.
45    fn ev_msg(&mut self, _port: u16, _msg: &str) {}
46
47    /// Called to indicate that a timer is firing.
48    fn ev_timer(&mut self, _timer: &dyn Any) {}
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    /// Test that default implementations are callable for all methods
56    #[test]
57    fn test_default_impls_callable() {
58        struct DefaultHandler;
59
60        impl EventHandler for DefaultHandler {}
61
62        let mut handler = DefaultHandler;
63
64        // These should not panic - testing default no-op impls
65        handler.ev_start(&dyn_any_placeholder());
66        handler.ev_pickup(&dyn_any_placeholder(), "node1");
67        handler.ev_read(&dyn_any_placeholder(), "node1", "stdout", "hello");
68        handler.ev_error(&dyn_any_placeholder());
69        handler.ev_written(&dyn_any_placeholder(), "node1", "stdout", 100);
70        handler.ev_hup(&dyn_any_placeholder(), "node1", 0);
71        handler.ev_close(&dyn_any_placeholder(), false);
72        handler._ev_routing(&dyn_any_placeholder(), "route_data");
73        handler.ev_msg(8080, "message");
74        handler.ev_timer(&dyn_any_placeholder());
75    }
76
77    /// Test that custom implementations can override specific methods
78    #[test]
79    fn test_custom_overrides() {
80        struct CustomHandler {
81            pub start_count: usize,
82            pub close_count: usize,
83        }
84
85        impl CustomHandler {
86            fn new() -> Self {
87                Self {
88                    start_count: 0,
89                    close_count: 0,
90                }
91            }
92        }
93
94        impl EventHandler for CustomHandler {
95            fn ev_start(&mut self, _worker: &dyn Any) {
96                self.start_count += 1;
97            }
98
99            fn ev_close(&mut self, _worker: &dyn Any, timedout: bool) {
100                self.close_count += 1;
101                assert!(!timedout, "Expected no timeout in this test");
102            }
103        }
104
105        let mut handler = CustomHandler::new();
106
107        handler.ev_start(&dyn_any_placeholder());
108        handler.ev_start(&dyn_any_placeholder());
109        handler.ev_close(&dyn_any_placeholder(), false);
110
111        assert_eq!(handler.start_count, 2, "ev_start should be called twice");
112        assert_eq!(handler.close_count, 1, "ev_close should be called once");
113    }
114
115    /// Test that the trait is object-safe and can be used as Box<dyn EventHandler>
116    ///
117    /// This test verifies that EventHandler is object-safe by:
118    /// 1. Creating Box<dyn EventHandler> from a concrete type
119    /// 2. Calling methods through the trait object
120    /// 3. Storing multiple handlers in a Vec<dyn EventHandler>
121    #[test]
122    fn test_object_safety() {
123        struct Handler1 {
124            pub count: usize,
125        }
126
127        impl EventHandler for Handler1 {
128            fn ev_start(&mut self, _worker: &dyn Any) {
129                self.count += 1;
130            }
131        }
132
133        struct Handler2 {
134            pub messages: Vec<String>,
135        }
136
137        impl EventHandler for Handler2 {
138            fn ev_read(&mut self, _worker: &dyn Any, node: &str, sname: &str, msg: &str) {
139                self.messages.push(format!("{}:{}:{}", node, sname, msg));
140            }
141        }
142
143        // This demonstrates object safety - we can store different handler types
144        // in a Vec of trait objects
145        let mut handlers: Vec<Box<dyn EventHandler>> = Vec::new();
146        handlers.push(Box::new(Handler1 { count: 0 }));
147        handlers.push(Box::new(Handler2 {
148            messages: Vec::new(),
149        }));
150
151        // Call ev_start on all handlers
152        for handler in &mut handlers {
153            handler.ev_start(&dyn_any_placeholder());
154        }
155
156        // Call ev_read on all handlers
157        for handler in &mut handlers {
158            handler.ev_read(&dyn_any_placeholder(), "node1", "stdout", "test");
159        }
160
161        // The fact that we can compile and run this code proves that
162        // EventHandler is object-safe. The trait object can be used
163        // polymorphically.
164        assert!(
165            true,
166            "Object safety test passed - Box<dyn EventHandler> works"
167        );
168    }
169
170    /// Helper to create a placeholder for dyn Any
171    fn dyn_any_placeholder() -> Box<dyn Any> {
172        Box::new(())
173    }
174
175    /// Test that EventHandler is Send and Sync (required for Box<dyn EventHandler>)
176    #[test]
177    fn test_send_sync() {
178        struct SendSyncHandler;
179
180        impl EventHandler for SendSyncHandler {}
181
182        fn assert_send<T: Send>() {}
183        fn assert_sync<T: Sync>() {}
184
185        assert_send::<Box<dyn EventHandler>>();
186        assert_sync::<Box<dyn EventHandler>>();
187        assert_send::<SendSyncHandler>();
188        assert_sync::<SendSyncHandler>();
189    }
190}