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> Default for CompositeErrorHandler<M> {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl<M> CompositeErrorHandler<M> {
76 pub fn new() -> Self {
78 Self {
79 handlers: Vec::new(),
80 }
81 }
82
83 pub fn add_handler(mut self, handler: Box<dyn ErrorHandler<M>>) -> Self {
85 self.handlers.push(handler);
86 self
87 }
88}
89
90impl<M> ErrorHandler<M> for CompositeErrorHandler<M> {
91 fn handle_error(&self, error: Error, tx: &SyncSender<Event<M>>) {
92 let error_string = error.to_string();
94 for handler in &self.handlers {
95 handler.handle_error(Error::Model(error_string.clone()), tx);
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use std::sync::mpsc;
104
105 #[derive(Clone, Debug, PartialEq)]
106 enum TestMsg {
107 Error(String),
108 }
109
110 #[test]
111 fn test_default_error_handler() {
112 let (tx, _rx) = mpsc::sync_channel::<Event<TestMsg>>(10);
113 let handler = DefaultErrorHandler;
114
115 let error = Error::Model("Test error".to_string());
116 handler.handle_error(error, &tx);
117
118 }
121
122 #[test]
123 fn test_event_error_handler() {
124 let (tx, rx) = mpsc::sync_channel(10);
125 let handler = EventErrorHandler::new(|err| TestMsg::Error(err.to_string()));
126
127 let error = Error::Model("Test error".to_string());
128 handler.handle_error(error, &tx);
129
130 let event = rx.recv().unwrap();
132 assert_eq!(
134 event,
135 Event::User(TestMsg::Error("Model error: Test error".to_string()))
136 );
137 }
138
139 #[test]
140 fn test_composite_error_handler() {
141 let (tx, rx) = mpsc::sync_channel(10);
142
143 let composite = CompositeErrorHandler::new()
144 .add_handler(Box::new(DefaultErrorHandler))
145 .add_handler(Box::new(EventErrorHandler::new(|err| {
146 TestMsg::Error(format!("Handled: {}", err))
147 })));
148
149 let error = Error::Model("Test error".to_string());
150 composite.handle_error(error, &tx);
151
152 let event = rx.recv().unwrap();
156 assert_eq!(
157 event,
158 Event::User(TestMsg::Error(
159 "Handled: Model error: Model error: Test error".to_string()
160 ))
161 );
162 }
163}