doum_cli/system/
error.rs

1use thiserror::Error;
2
3/// doum-cli에서 사용하는 결과 타입
4pub type DoumResult<T> = std::result::Result<T, DoumError>;
5
6/// doum-cli의 모든 에러 타입
7#[derive(Error, Debug)]
8pub enum DoumError {
9    /// 설정 관련 에러
10    #[error("Configuration error: {0}")]
11    Config(String),
12
13    /// LLM API 관련 에러
14    #[error("LLM API error: {0}")]
15    LLM(String),
16
17    /// 응답 파싱 에러
18    #[error("Parse error: {0}")]
19    Parse(String),
20
21    /// IO 에러
22    #[error("IO error: {0}")]
23    Io(#[from] std::io::Error),
24
25    /// 명령 실행 에러
26    #[error("Command execution failed: {0}")]
27    CommandExecution(String),
28
29    /// 사용자 취소
30    #[error("User cancelled operation")]
31    UserCancelled,
32
33    /// 잘못된 설정
34    #[error("Invalid configuration: {0}")]
35    InvalidConfig(String),
36
37    /// 타임아웃
38    #[error("Request timeout")]
39    Timeout,
40
41    /// Reqwest 에러
42    #[error("HTTP request error: {0}")]
43    Reqwest(#[from] reqwest::Error),
44
45    /// JSON 직렬화/역직렬화 에러
46    #[error("JSON error: {0}")]
47    Json(#[from] serde_json::Error),
48
49    /// TOML 직렬화/역직렬화 에러
50    #[error("TOML error: {0}")]
51    Toml(#[from] toml::de::Error),
52
53    /// Dialoguer 에러
54    #[error("User interaction error: {0}")]
55    Dialoguer(String),
56}
57
58impl DoumError {
59    /// Return a short, user-friendly error message
60    pub fn user_message(&self) -> String {
61        match self {
62            DoumError::Config(msg) => {
63                format!("Configuration error: {}", msg)
64            }
65            DoumError::LLM(msg) => {
66                if msg.contains("401") || msg.contains("unauthorized") {
67                    format!(
68                        "Authentication error (LLM API): {}. Check your API key.",
69                        msg
70                    )
71                } else if msg.contains("timeout") || msg.contains("timed out") {
72                    "LLM request timed out. Please try again or increase the timeout.".to_string()
73                } else if msg.contains("rate limit") || msg.contains("429") {
74                    "Rate limit exceeded. Please wait a moment and try again.".to_string()
75                } else {
76                    format!("LLM API error: {}", msg)
77                }
78            }
79            DoumError::Parse(msg) => {
80                format!("Failed to parse LLM response: {}", msg)
81            }
82            DoumError::Io(err) => {
83                format!("I/O error: {}", err)
84            }
85            DoumError::CommandExecution(msg) => {
86                format!("Command execution failed: {}", msg)
87            }
88            DoumError::UserCancelled => "Operation cancelled by user.".to_string(),
89            DoumError::InvalidConfig(msg) => {
90                format!("Invalid configuration: {}", msg)
91            }
92            DoumError::Timeout => "Request timed out. Please try again.".to_string(),
93            DoumError::Reqwest(err) => {
94                if err.is_timeout() {
95                    "Network timeout. Please check your connection and try again.".to_string()
96                } else if err.is_connect() {
97                    "Failed to connect to server. Please check your network connection.".to_string()
98                } else {
99                    format!("Network error: {}", err)
100                }
101            }
102            DoumError::Json(err) => {
103                format!("JSON error: {}", err)
104            }
105            DoumError::Toml(err) => {
106                format!("TOML error: {}", err)
107            }
108            DoumError::Dialoguer(msg) => {
109                format!("User interaction error: {}", msg)
110            }
111        }
112    }
113}
114
115impl From<dialoguer::Error> for DoumError {
116    fn from(err: dialoguer::Error) -> Self {
117        DoumError::Dialoguer(err.to_string())
118    }
119}