1use std::fmt;
4
5#[derive(Debug)]
7pub enum TranslationError {
8 NetworkError(reqwest::Error),
10 HttpError {
12 status: reqwest::StatusCode,
13 body: String,
14 },
15 AuthenticationError(String),
17 TimeoutError,
19 MaxRetriesExceeded {
21 attempts: u32,
22 errors: Vec<TranslationError>, },
24 ServiceError(String),
26 ConfigurationError(String),
28 Other(String),
30}
31
32impl TranslationError {
33 pub fn is_retryable(&self) -> bool {
35 match self {
36 TranslationError::NetworkError(_) => true,
37 TranslationError::HttpError { status, .. } => {
38 status.is_server_error()
40 }
41 TranslationError::TimeoutError => true,
42 _ => false,
44 }
45 }
46}
47
48impl fmt::Display for TranslationError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 TranslationError::NetworkError(e) => write!(f, "Network error: {}", e),
52 TranslationError::HttpError { status, body } => {
53 write!(f, "HTTP error {}: {}", status, body)
54 }
55 TranslationError::AuthenticationError(msg) => {
56 write!(f, "Authentication error: {}", msg)
57 }
58 TranslationError::TimeoutError => write!(f, "Request timeout"),
59 TranslationError::MaxRetriesExceeded { attempts, errors } => {
60 writeln!(f, "Max retries exceeded after {} attempts", attempts)?;
61 for (i, error) in errors.iter().enumerate() {
62 writeln!(f, " Attempt {}: {}", i + 1, error)?;
63 }
64 Ok(())
65 }
66 TranslationError::ServiceError(msg) => write!(f, "Service error: {}", msg),
67 TranslationError::ConfigurationError(msg) => write!(f, "Configuration error: {}", msg),
68 TranslationError::Other(msg) => write!(f, "Error: {}", msg),
69 }
70 }
71}
72
73impl std::error::Error for TranslationError {
74 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
75 match self {
76 TranslationError::NetworkError(e) => Some(e),
77 TranslationError::MaxRetriesExceeded { .. } => None,
78 _ => None,
79 }
80 }
81}
82
83impl From<reqwest::Error> for TranslationError {
85 fn from(error: reqwest::Error) -> Self {
86 if error.is_timeout() {
87 TranslationError::TimeoutError
88 } else if error.is_connect() {
89 TranslationError::NetworkError(error)
90 } else {
91 TranslationError::NetworkError(error)
92 }
93 }
94}
95
96impl From<serde_json::Error> for TranslationError {
97 fn from(error: serde_json::Error) -> Self {
98 TranslationError::ServiceError(format!("JSON parsing error: {}", error))
99 }
100}
101
102impl From<anyhow::Error> for TranslationError {
103 fn from(error: anyhow::Error) -> Self {
104 TranslationError::Other(error.to_string())
105 }
106}