hojicha_runtime/program/
error_handler.rs1use hojicha_core::error::Error;
7use hojicha_core::event::Event;
8use std::sync::mpsc::SyncSender;
9
10pub trait ErrorHandler<M>: Send + Sync {
12 fn handle_error(&self, error: Error, tx: &SyncSender<Event<M>>);
14}
15
16pub struct DefaultErrorHandler;
18
19impl<M> ErrorHandler<M> for DefaultErrorHandler {
20 fn handle_error(&self, error: Error, _tx: &SyncSender<Event<M>>) {
21 eprintln!("Command execution error: {}", error);
22
23 let mut current_error: &dyn std::error::Error = &error;
25 while let Some(source) = current_error.source() {
26 eprintln!(" Caused by: {}", source);
27 current_error = source;
28 }
29 }
30}
31
32pub struct EventErrorHandler<M, F>
34where
35 M: Clone + Send + 'static,
36 F: Fn(Error) -> M + Send + Sync,
37{
38 converter: F,
39}
40
41impl<M, F> EventErrorHandler<M, F>
42where
43 M: Clone + Send + 'static,
44 F: Fn(Error) -> M + Send + Sync,
45{
46 pub fn new(converter: F) -> Self {
48 Self { converter }
49 }
50}
51
52impl<M, F> ErrorHandler<M> for EventErrorHandler<M, F>
53where
54 M: Clone + Send + 'static,
55 F: Fn(Error) -> M + Send + Sync,
56{
57 fn handle_error(&self, error: Error, tx: &SyncSender<Event<M>>) {
58 let msg = (self.converter)(error);
60 let _ = tx.send(Event::User(msg));
61 }
62}
63
64pub struct CompositeErrorHandler<M> {
66 handlers: Vec<Box<dyn ErrorHandler<M>>>,
67}
68
69impl<M> CompositeErrorHandler<M> {
70 pub fn new() -> Self {
72 Self {
73 handlers: Vec::new(),
74 }
75 }
76
77 pub fn add_handler(mut self, handler: Box<dyn ErrorHandler<M>>) -> Self {
79 self.handlers.push(handler);
80 self
81 }
82}
83
84impl<M> ErrorHandler<M> for CompositeErrorHandler<M> {
85 fn handle_error(&self, error: Error, tx: &SyncSender<Event<M>>) {
86 let error_string = error.to_string();
88 for handler in &self.handlers {
89 handler.handle_error(Error::Model(error_string.clone()), tx);
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use std::sync::mpsc;
98
99 #[derive(Clone, Debug, PartialEq)]
100 enum TestMsg {
101 Error(String),
102 }
103
104 #[test]
105 fn test_default_error_handler() {
106 let (tx, _rx) = mpsc::sync_channel::<Event<TestMsg>>(10);
107 let handler = DefaultErrorHandler;
108
109 let error = Error::Model("Test error".to_string());
110 handler.handle_error(error, &tx);
111
112 }
115
116 #[test]
117 fn test_event_error_handler() {
118 let (tx, rx) = mpsc::sync_channel(10);
119 let handler = EventErrorHandler::new(|err| TestMsg::Error(err.to_string()));
120
121 let error = Error::Model("Test error".to_string());
122 handler.handle_error(error, &tx);
123
124 let event = rx.recv().unwrap();
126 assert_eq!(event, Event::User(TestMsg::Error("Model error: Test error".to_string())));
128 }
129
130 #[test]
131 fn test_composite_error_handler() {
132 let (tx, rx) = mpsc::sync_channel(10);
133
134 let composite = CompositeErrorHandler::new()
135 .add_handler(Box::new(DefaultErrorHandler))
136 .add_handler(Box::new(EventErrorHandler::new(|err| {
137 TestMsg::Error(format!("Handled: {}", err))
138 })));
139
140 let error = Error::Model("Test error".to_string());
141 composite.handle_error(error, &tx);
142
143 let event = rx.recv().unwrap();
147 assert_eq!(event, Event::User(TestMsg::Error("Handled: Model error: Model error: Test error".to_string())));
148 }
149}