1use thiserror::Error;
8
9#[derive(Error, Debug)]
11pub enum GenesisError {
12 #[error("DNA error: {0}")]
13 DNA(#[from] crate::dna::DNAError),
14
15 #[error("TRON organism error: {0}")]
16 TRON(#[from] crate::tron::TRONError),
17
18 #[error("Neural communication error: {0}")]
19 Neural(#[from] crate::neural::SynapseError),
20
21 #[error("Evolution error: {0}")]
22 Evolution(#[from] crate::evolution::EvolutionError),
23
24 #[error("Collective intelligence error: {0}")]
25 Collective(#[from] crate::collective::CollectiveError),
26
27 #[error("Network error: {0}")]
28 Network(#[from] crate::network::NetworkError),
29
30 #[error("Organism not found: {0}")]
31 OrganismNotFound(String),
32
33 #[error("Network capacity exceeded: {current} organisms (max: {max})")]
34 NetworkCapacityExceeded { current: usize, max: usize },
35
36 #[error("Protocol version mismatch: expected {expected}, got {actual}")]
37 ProtocolVersionMismatch { expected: String, actual: String },
38
39 #[error("Invalid configuration: {0}")]
40 InvalidConfiguration(String),
41
42 #[error("Insufficient resources: {resource}")]
43 InsufficientResources { resource: String },
44
45 #[error("Operation timeout: {operation} took longer than {timeout_ms}ms")]
46 OperationTimeout { operation: String, timeout_ms: u64 },
47
48 #[error("Security violation: {0}")]
49 SecurityViolation(String),
50
51 #[error("IO error: {0}")]
52 IO(#[from] std::io::Error),
53
54 #[error("Serialization error: {0}")]
55 Serialization(#[from] serde_json::Error),
56
57 #[error("Internal error: {0}")]
58 Internal(String),
59}
60
61pub type GenesisResult<T> = Result<T, GenesisError>;
63
64#[derive(Debug, Clone, Copy)]
66pub enum ErrorRecovery {
67 Retry,
69 Fallback,
71 Degrade,
73 Fail,
75}
76
77#[derive(Debug, Clone)]
79pub struct ErrorContext {
80 pub operation: String,
81 pub organism_id: Option<String>,
82 pub timestamp: u64,
83 pub recovery_strategy: ErrorRecovery,
84 pub metadata: std::collections::HashMap<String, String>,
85}
86
87impl ErrorContext {
88 pub fn new(operation: &str) -> Self {
89 ErrorContext {
90 operation: operation.to_string(),
91 organism_id: None,
92 timestamp: std::time::SystemTime::now()
93 .duration_since(std::time::UNIX_EPOCH)
94 .unwrap()
95 .as_secs(),
96 recovery_strategy: ErrorRecovery::Fail,
97 metadata: std::collections::HashMap::new(),
98 }
99 }
100
101 pub fn with_organism(mut self, organism_id: &str) -> Self {
102 self.organism_id = Some(organism_id.to_string());
103 self
104 }
105
106 pub fn with_recovery(mut self, strategy: ErrorRecovery) -> Self {
107 self.recovery_strategy = strategy;
108 self
109 }
110
111 pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
112 self.metadata.insert(key.to_string(), value.to_string());
113 self
114 }
115}
116
117#[derive(Debug)]
119pub struct ContextualError {
120 pub error: GenesisError,
121 pub context: ErrorContext,
122 pub source_location: Option<String>,
123}
124
125impl ContextualError {
126 pub fn new(error: GenesisError, context: ErrorContext) -> Self {
127 ContextualError {
128 error,
129 context,
130 source_location: None,
131 }
132 }
133
134 pub fn with_location(mut self, location: &str) -> Self {
135 self.source_location = Some(location.to_string());
136 self
137 }
138}
139
140impl std::fmt::Display for ContextualError {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 write!(f, "Error in {}: {}", self.context.operation, self.error)?;
143 if let Some(organism_id) = &self.context.organism_id {
144 write!(f, " (organism: {})", organism_id)?;
145 }
146 if let Some(location) = &self.source_location {
147 write!(f, " at {}", location)?;
148 }
149 Ok(())
150 }
151}
152
153impl std::error::Error for ContextualError {
154 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
155 Some(&self.error)
156 }
157}
158
159#[macro_export]
161macro_rules! genesis_error {
162 ($error:expr, $operation:expr) => {
163 ContextualError::new(
164 $error.into(),
165 ErrorContext::new($operation)
166 ).with_location(&format!("{}:{}", file!(), line!()))
167 };
168
169 ($error:expr, $operation:expr, $organism_id:expr) => {
170 ContextualError::new(
171 $error.into(),
172 ErrorContext::new($operation).with_organism($organism_id)
173 ).with_location(&format!("{}:{}", file!(), line!()))
174 };
175
176 ($error:expr, $operation:expr, $organism_id:expr, $recovery:expr) => {
177 ContextualError::new(
178 $error.into(),
179 ErrorContext::new($operation)
180 .with_organism($organism_id)
181 .with_recovery($recovery)
182 ).with_location(&format!("{}:{}", file!(), line!()))
183 };
184}
185
186#[derive(Debug, Clone)]
188pub struct ErrorMetrics {
189 pub total_errors: u64,
190 pub errors_by_type: std::collections::HashMap<String, u64>,
191 pub errors_by_organism: std::collections::HashMap<String, u64>,
192 pub recovery_attempts: u64,
193 pub successful_recoveries: u64,
194 pub last_error_time: u64,
195}
196
197impl ErrorMetrics {
198 pub fn new() -> Self {
199 ErrorMetrics {
200 total_errors: 0,
201 errors_by_type: std::collections::HashMap::new(),
202 errors_by_organism: std::collections::HashMap::new(),
203 recovery_attempts: 0,
204 successful_recoveries: 0,
205 last_error_time: 0,
206 }
207 }
208
209 pub fn record_error(&mut self, error: &GenesisError, organism_id: Option<&str>) {
210 self.total_errors += 1;
211 self.last_error_time = std::time::SystemTime::now()
212 .duration_since(std::time::UNIX_EPOCH)
213 .unwrap()
214 .as_secs();
215
216 let error_type = match error {
217 GenesisError::DNA(_) => "DNA",
218 GenesisError::TRON(_) => "TRON",
219 GenesisError::Neural(_) => "Neural",
220 GenesisError::Evolution(_) => "Evolution",
221 GenesisError::Collective(_) => "Collective",
222 GenesisError::Network(_) => "Network",
223 GenesisError::OrganismNotFound(_) => "OrganismNotFound",
224 GenesisError::NetworkCapacityExceeded { .. } => "NetworkCapacityExceeded",
225 GenesisError::ProtocolVersionMismatch { .. } => "ProtocolVersionMismatch",
226 GenesisError::InvalidConfiguration(_) => "InvalidConfiguration",
227 GenesisError::InsufficientResources { .. } => "InsufficientResources",
228 GenesisError::OperationTimeout { .. } => "OperationTimeout",
229 GenesisError::SecurityViolation(_) => "SecurityViolation",
230 GenesisError::IO(_) => "IO",
231 GenesisError::Serialization(_) => "Serialization",
232 GenesisError::Internal(_) => "Internal",
233 };
234
235 *self.errors_by_type.entry(error_type.to_string()).or_insert(0) += 1;
236
237 if let Some(organism_id) = organism_id {
238 *self.errors_by_organism.entry(organism_id.to_string()).or_insert(0) += 1;
239 }
240 }
241
242 pub fn record_recovery_attempt(&mut self, successful: bool) {
243 self.recovery_attempts += 1;
244 if successful {
245 self.successful_recoveries += 1;
246 }
247 }
248
249 pub fn get_error_rate(&self) -> f64 {
250 if self.total_errors == 0 {
251 0.0
252 } else {
253 self.total_errors as f64 / std::time::SystemTime::now()
254 .duration_since(std::time::UNIX_EPOCH)
255 .unwrap()
256 .as_secs() as f64
257 }
258 }
259
260 pub fn get_recovery_rate(&self) -> f64 {
261 if self.recovery_attempts == 0 {
262 0.0
263 } else {
264 self.successful_recoveries as f64 / self.recovery_attempts as f64
265 }
266 }
267}
268
269impl Default for ErrorMetrics {
270 fn default() -> Self {
271 Self::new()
272 }
273}
274
275pub trait ErrorHandler {
277 fn handle_error(&self, error: &GenesisError, context: &ErrorContext) -> ErrorRecovery;
278 fn should_retry(&self, error: &GenesisError, attempt: u32) -> bool;
279 fn get_retry_delay(&self, error: &GenesisError, attempt: u32) -> std::time::Duration;
280}
281
282pub struct DefaultErrorHandler {
284 max_retries: u32,
285 base_delay_ms: u64,
286}
287
288impl DefaultErrorHandler {
289 pub fn new() -> Self {
290 DefaultErrorHandler {
291 max_retries: 3,
292 base_delay_ms: 100,
293 }
294 }
295
296 pub fn with_max_retries(mut self, max_retries: u32) -> Self {
297 self.max_retries = max_retries;
298 self
299 }
300
301 pub fn with_base_delay(mut self, delay_ms: u64) -> Self {
302 self.base_delay_ms = delay_ms;
303 self
304 }
305}
306
307impl ErrorHandler for DefaultErrorHandler {
308 fn handle_error(&self, error: &GenesisError, _context: &ErrorContext) -> ErrorRecovery {
309 match error {
310 GenesisError::Neural(_) => ErrorRecovery::Retry,
311 GenesisError::Network(_) => ErrorRecovery::Retry,
312 GenesisError::OperationTimeout { .. } => ErrorRecovery::Retry,
313 GenesisError::InsufficientResources { .. } => ErrorRecovery::Degrade,
314 GenesisError::NetworkCapacityExceeded { .. } => ErrorRecovery::Degrade,
315 GenesisError::DNA(_) => ErrorRecovery::Fail,
316 GenesisError::TRON(_) => ErrorRecovery::Fallback,
317 GenesisError::Evolution(_) => ErrorRecovery::Fallback,
318 GenesisError::SecurityViolation(_) => ErrorRecovery::Fail,
319 _ => ErrorRecovery::Fail,
320 }
321 }
322
323 fn should_retry(&self, error: &GenesisError, attempt: u32) -> bool {
324 if attempt >= self.max_retries {
325 return false;
326 }
327
328 match error {
329 GenesisError::Neural(_) => true,
330 GenesisError::Network(_) => true,
331 GenesisError::OperationTimeout { .. } => true,
332 GenesisError::IO(_) => true,
333 _ => false,
334 }
335 }
336
337 fn get_retry_delay(&self, _error: &GenesisError, attempt: u32) -> std::time::Duration {
338 let delay_ms = self.base_delay_ms * (2_u64.pow(attempt));
340 std::time::Duration::from_millis(delay_ms)
341 }
342}
343
344impl Default for DefaultErrorHandler {
345 fn default() -> Self {
346 Self::new()
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353 use crate::dna::DNAError;
354
355 #[test]
356 fn test_genesis_error_conversion() {
357 let dna_error = DNAError::InvalidSecretKey;
358 let genesis_error: GenesisError = dna_error.into();
359
360 match genesis_error {
361 GenesisError::DNA(DNAError::InvalidSecretKey) => {},
362 _ => panic!("Error conversion failed"),
363 }
364 }
365
366 #[test]
367 fn test_error_context() {
368 let context = ErrorContext::new("test_operation")
369 .with_organism("tron_123")
370 .with_recovery(ErrorRecovery::Retry)
371 .with_metadata("key", "value");
372
373 assert_eq!(context.operation, "test_operation");
374 assert_eq!(context.organism_id, Some("tron_123".to_string()));
375 assert!(matches!(context.recovery_strategy, ErrorRecovery::Retry));
376 assert_eq!(context.metadata.get("key"), Some(&"value".to_string()));
377 }
378
379 #[test]
380 fn test_contextual_error() {
381 let error = GenesisError::OrganismNotFound("tron_123".to_string());
382 let context = ErrorContext::new("neural_connect");
383 let contextual = ContextualError::new(error, context)
384 .with_location("test.rs:42");
385
386 let error_string = contextual.to_string();
387 assert!(error_string.contains("neural_connect"));
388 assert!(error_string.contains("test.rs:42"));
389 }
390
391 #[test]
392 fn test_error_metrics() {
393 let mut metrics = ErrorMetrics::new();
394
395 let error = GenesisError::DNA(DNAError::InvalidSecretKey);
396 metrics.record_error(&error, Some("tron_123"));
397
398 assert_eq!(metrics.total_errors, 1);
399 assert_eq!(metrics.errors_by_type.get("DNA"), Some(&1));
400 assert_eq!(metrics.errors_by_organism.get("tron_123"), Some(&1));
401
402 metrics.record_recovery_attempt(true);
403 assert_eq!(metrics.recovery_attempts, 1);
404 assert_eq!(metrics.successful_recoveries, 1);
405 assert_eq!(metrics.get_recovery_rate(), 1.0);
406 }
407
408 #[test]
409 fn test_default_error_handler() {
410 let handler = DefaultErrorHandler::new();
411
412 let neural_error = GenesisError::Neural(crate::neural::SynapseError::ConnectionRefused);
413 let context = ErrorContext::new("test");
414
415 assert!(matches!(handler.handle_error(&neural_error, &context), ErrorRecovery::Retry));
416 assert!(handler.should_retry(&neural_error, 1));
417 assert!(!handler.should_retry(&neural_error, 5));
418
419 let delay = handler.get_retry_delay(&neural_error, 1);
420 assert_eq!(delay, std::time::Duration::from_millis(200));
421 }
422}