huawei_dongle_api/
error.rs1use thiserror::Error;
4
5pub mod error_codes {
45 pub const NO_RIGHTS: i32 = 100003;
46 pub const CSRF_TOKEN_ERROR: i32 = 125002;
47 pub const SESSION_TOKEN_ERROR: i32 = 125003;
48 pub const USERNAME_WRONG: i32 = 108001;
49 pub const PASSWORD_WRONG: i32 = 108002;
50 pub const ALREADY_LOGIN: i32 = 108003;
51 pub const USERNAME_PWD_WRONG: i32 = 108006;
52 pub const USERNAME_PWD_OVERRUN: i32 = 108007;
53}
54
55pub type Result<T> = std::result::Result<T, Error>;
57
58#[derive(Error, Debug)]
60pub enum Error {
61 #[error("HTTP request failed: {0}")]
63 Http(#[from] reqwest::Error),
64
65 #[error("XML parsing failed: {0}")]
67 Xml(#[from] serde_xml_rs::Error),
68
69 #[error("XML parsing failed: {0}")]
71 QuickXml(#[from] quick_xml::Error),
72
73 #[error("Invalid URL: {0}")]
75 Url(#[from] url::ParseError),
76
77 #[error("Authentication failed: {message}")]
79 Authentication { message: String },
80
81 #[error("Login required")]
83 LoginRequired,
84
85 #[error("Invalid username")]
87 InvalidUsername,
88
89 #[error("Invalid password")]
91 InvalidPassword,
92
93 #[error("Invalid username or password")]
95 InvalidCredentials,
96
97 #[error("Too many login attempts")]
99 TooManyLoginAttempts,
100
101 #[error("Already logged in")]
103 AlreadyLoggedIn,
104
105 #[error("CSRF token invalid")]
107 CsrfTokenInvalid,
108
109 #[error("Session token invalid")]
111 SessionTokenInvalid,
112
113 #[error("API error {code}: {message}")]
115 Api { code: i32, message: String },
116
117 #[error("Session error: {message}")]
119 Session { message: String },
120
121 #[error("Configuration error: {message}")]
123 Config { message: String },
124
125 #[error("Error: {message}")]
127 Generic { message: String },
128}
129
130impl Error {
131 pub fn is_retryable(&self) -> bool {
133 match self {
134 Error::Http(e) => {
135 if e.is_timeout() || e.is_connect() {
136 return true;
137 }
138 if let Some(status) = e.status() {
139 return !status.is_client_error();
140 }
141 true
142 }
143 Error::Api { code, .. } => *code >= 500 && *code < 600,
144 Error::Session { .. } => true,
145 Error::LoginRequired => false,
146 Error::InvalidUsername => false,
147 Error::InvalidPassword => false,
148 Error::InvalidCredentials => false,
149 Error::TooManyLoginAttempts => false,
150 Error::AlreadyLoggedIn => false,
151 Error::CsrfTokenInvalid => true,
152 Error::SessionTokenInvalid => true,
153 _ => false,
154 }
155 }
156
157 pub fn authentication<S: Into<String>>(message: S) -> Self {
159 Self::Authentication {
160 message: message.into(),
161 }
162 }
163
164 pub fn api(code: i32, message: String) -> Self {
166 use error_codes::*;
167
168 match code {
169 NO_RIGHTS => Self::LoginRequired,
170 CSRF_TOKEN_ERROR => Self::CsrfTokenInvalid,
171 SESSION_TOKEN_ERROR => Self::SessionTokenInvalid,
172 USERNAME_WRONG => Self::InvalidUsername,
173 PASSWORD_WRONG => Self::InvalidPassword,
174 ALREADY_LOGIN => Self::AlreadyLoggedIn,
175 USERNAME_PWD_WRONG => Self::InvalidCredentials,
176 USERNAME_PWD_OVERRUN => Self::TooManyLoginAttempts,
177 _ => Self::Api { code, message },
178 }
179 }
180
181 pub fn session<S: Into<String>>(message: S) -> Self {
183 Self::Session {
184 message: message.into(),
185 }
186 }
187
188 pub fn config<S: Into<String>>(message: S) -> Self {
190 Self::Config {
191 message: message.into(),
192 }
193 }
194
195 pub fn generic<S: Into<String>>(message: S) -> Self {
197 Self::Generic {
198 message: message.into(),
199 }
200 }
201}