1use std::fmt;
4use thiserror::Error;
5use uuid::Uuid;
6
7pub type Result<T> = std::result::Result<T, Error>;
9
10#[derive(Error, Debug)]
12pub enum Error {
13 #[error("Failed to publish event: {0}")]
15 PublishError(String),
16
17 #[error("Failed to subscribe: {0}")]
19 SubscriptionError(String),
20
21 #[error("Event type not registered: {type_name}")]
23 EventNotRegistered {
24 type_name: String,
26 },
27
28 #[error("Subscription not found: {id}")]
30 SubscriptionNotFound {
31 id: Uuid,
33 },
34
35 #[error("Handler error: {0}")]
37 HandlerError(String),
38
39 #[error("Event bus is shutting down")]
41 ShuttingDown,
42
43 #[error("Failed to send through channel")]
45 ChannelSendError,
46
47 #[error("Failed to receive from channel")]
49 ChannelReceiveError,
50
51 #[error("Serialization error: {0}")]
53 SerializationError(String),
54
55 #[error("Configuration error: {0}")]
57 ConfigError(String),
58
59 #[error("Internal error: {0}")]
61 Internal(String),
62}
63
64impl Error {
65 pub fn internal(msg: impl Into<String>) -> Self {
67 Error::Internal(msg.into())
68 }
69
70 pub fn handler(msg: impl Into<String>) -> Self {
72 Error::HandlerError(msg.into())
73 }
74
75 pub fn is_shutdown(&self) -> bool {
77 matches!(self, Error::ShuttingDown)
78 }
79
80 pub fn is_channel_error(&self) -> bool {
82 matches!(self, Error::ChannelSendError | Error::ChannelReceiveError)
83 }
84}
85
86#[derive(Debug)]
88pub struct ErrorContext {
89 pub event_id: Option<Uuid>,
91 pub event_type: Option<String>,
93 pub handler_name: Option<String>,
95 pub timestamp: chrono::DateTime<chrono::Utc>,
97}
98
99impl Default for ErrorContext {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl ErrorContext {
106 pub fn new() -> Self {
108 Self {
109 event_id: None,
110 event_type: None,
111 handler_name: None,
112 timestamp: chrono::Utc::now(),
113 }
114 }
115
116 pub fn with_event_id(mut self, id: Uuid) -> Self {
118 self.event_id = Some(id);
119 self
120 }
121
122 pub fn with_event_type(mut self, event_type: impl Into<String>) -> Self {
124 self.event_type = Some(event_type.into());
125 self
126 }
127
128 pub fn with_handler(mut self, name: impl Into<String>) -> Self {
130 self.handler_name = Some(name.into());
131 self
132 }
133}
134
135impl fmt::Display for ErrorContext {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 write!(f, "Error at {}", self.timestamp)?;
138 if let Some(id) = &self.event_id {
139 write!(f, " [event_id: {}]", id)?;
140 }
141 if let Some(event_type) = &self.event_type {
142 write!(f, " [type: {}]", event_type)?;
143 }
144 if let Some(handler) = &self.handler_name {
145 write!(f, " [handler: {}]", handler)?;
146 }
147 Ok(())
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_error_display() {
157 let err = Error::PublishError("test error".to_string());
158 assert_eq!(err.to_string(), "Failed to publish event: test error");
159 }
160
161 #[test]
162 fn test_error_is_shutdown() {
163 assert!(Error::ShuttingDown.is_shutdown());
164 assert!(!Error::internal("test").is_shutdown());
165 }
166
167 #[test]
168 fn test_error_context() {
169 let ctx = ErrorContext::new()
170 .with_event_id(Uuid::max())
171 .with_event_type("TestEvent")
172 .with_handler("test_handler");
173
174 let display = ctx.to_string();
175 assert!(display.contains("TestEvent"));
176 assert!(display.contains("test_handler"));
177 }
178}