1use std::collections::HashMap;
17use std::error::Error;
18use std::fmt::{Debug, Display, Formatter};
19
20use serde::Deserialize;
21
22use crate::common::RequestInfo;
23
24pub type CommonError = std::io::Error;
25
26#[derive(Debug, Clone, PartialEq)]
27pub enum GenericError {
28 UrlParseError(url::ParseError),
29 DateTimeParseError(chrono::ParseError),
30 HttpRequestError(String),
31 IoError(String),
32 JsonError(String),
33 DefaultError(String),
34}
35
36impl Error for GenericError {}
37
38impl Display for GenericError {
39 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40 match self {
41 GenericError::UrlParseError(e) => {
42 write!(f, "{}", e.to_string())
43 }
44 GenericError::DateTimeParseError(e) => {
45 write!(f, "{}", e.to_string())
46 }
47 GenericError::DefaultError(e) => {
48 write!(f, "{}", e)
49 }
50 GenericError::HttpRequestError(e) => {
51 write!(f, "{}", e)
52 }
53 GenericError::IoError(e) => {
54 write!(f, "{}", e)
55 }
56 GenericError::JsonError(e) => {
57 write!(f, "{}", e)
58 }
59 }
60 }
61}
62
63#[derive(Debug, Clone, PartialEq)]
64pub enum TosError {
65 TosClientError {
66 message: String,
67 cause: Option<GenericError>,
68 request_url: String,
69 },
70 TosServerError {
71 message: String,
72 code: String,
73 host_id: String,
74 resource: String,
75 status_code: isize,
76 request_id: String,
77 ec: String,
78 key: String,
79 id2: String,
80 header: HashMap<String, String>,
81 request_url: String,
82 },
83}
84
85impl Error for TosError {
86 fn source(&self) -> Option<&(dyn Error + 'static)> {
87 match self {
88 TosError::TosClientError { cause, .. } => {
89 if let Some(x) = cause {
90 return Some(x);
91 }
92 None
93 }
94 TosError::TosServerError { .. } => None,
95 }
96 }
97}
98
99impl Display for TosError {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 write!(f, "{}", self.error())
102 }
103}
104
105impl TosError {
106 pub fn message(&self) -> &str {
107 match self {
108 Self::TosClientError { message, .. } => message,
109 Self::TosServerError { message, .. } => message,
110 }
111 }
112
113 pub fn request_url(&self) -> &str {
114 match self {
115 Self::TosClientError { request_url, .. } => request_url,
116 Self::TosServerError { request_url, .. } => request_url,
117 }
118 }
119
120 pub fn is_server_error(&self) -> bool {
121 match self {
122 Self::TosClientError { .. } => false,
123 Self::TosServerError { .. } => true,
124 }
125 }
126
127 pub fn as_server_error(&self) -> Option<TosServerError> {
128 match self {
129 Self::TosClientError { .. } => None,
130 Self::TosServerError {
131 message, code, host_id,
132 resource, status_code, request_id,
133 ec, id2, header, request_url, key,
134 } => Some(TosServerError {
135 message,
136 request_url,
137 code,
138 host_id,
139 resource,
140 status_code: status_code.to_owned(),
141 request_id,
142 ec,
143 key,
144 id2,
145 header,
146 }),
147 }
148 }
149
150 pub fn error(&self) -> String {
151 match self {
152 Self::TosClientError { message, cause, .. } => {
153 if let Some(e) = cause {
154 format!("message: {}, cause: {}", message, e)
155 } else {
156 format!("message: {}", message)
157 }
158 }
159 Self::TosServerError { status_code, code, ec, request_id, message, .. } => {
160 if ec == "" {
161 format!("status_code: {}, code: {}, request_id: {}, message: {}", status_code, code, request_id, message)
162 } else {
163 format!("status_code: {}, code: {}, request_id: {}, ec: {}, message: {}", status_code, code, request_id, ec, message)
164 }
165 }
166 }
167 }
168
169 pub fn as_request_info(&self) -> Option<RequestInfo> {
170 match self {
171 Self::TosClientError { .. } => None::<RequestInfo>,
172 Self::TosServerError { request_id, id2, status_code, header, .. } => Some(RequestInfo {
173 request_id: request_id.to_string(),
174 id2: id2.to_string(),
175 status_code: status_code.to_owned(),
176 header: header.to_owned(),
177 }),
178 }
179 }
180
181 pub(crate) fn set_request_url(&mut self, url: impl Into<String>) {
182 match self {
183 TosError::TosClientError { request_url, .. } => {
184 *request_url = url.into();
185 }
186 TosError::TosServerError { request_url, .. } => {
187 *request_url = url.into();
188 }
189 }
190 }
191
192 pub(crate) fn client_error(message: impl Into<String>) -> Self {
193 Self::TosClientError {
194 message: message.into(),
195 request_url: "".to_string(),
196 cause: None,
197 }
198 }
199
200 pub(crate) fn client_error_with_cause(message: impl Into<String>, cause: GenericError) -> Self {
201 Self::TosClientError {
202 message: message.into(),
203 request_url: "".to_string(),
204 cause: Some(cause),
205 }
206 }
207
208 pub(crate) fn client_error_result(message: impl Into<String>) -> Result<(), TosError> {
209 Err(Self::client_error(message))
210 }
211
212 pub(crate) fn client_error_result_with_cause(message: impl Into<String>, cause: GenericError) -> Result<(), TosError> {
213 Err(Self::client_error_with_cause(message, cause))
214 }
215
216 pub(crate) fn server_error(message: impl Into<String>, request_info: RequestInfo) -> Self {
217 Self::TosServerError {
218 message: message.into(),
219 request_url: "".to_string(),
220 code: "".to_string(),
221 host_id: "".to_string(),
222 resource: "".to_string(),
223 status_code: request_info.status_code,
224 request_id: request_info.request_id,
225 ec: "".to_string(),
226 key: "".to_string(),
227 id2: request_info.id2,
228 header: request_info.header,
229 }
230 }
231
232 pub(crate) fn server_error_with_code(code: impl Into<String>, ec: impl Into<String>, key: impl Into<String>, message: impl Into<String>, host_id: impl Into<String>,
233 resource: impl Into<String>, request_info: RequestInfo) -> Self {
234 Self::TosServerError {
235 message: message.into(),
236 request_url: "".to_string(),
237 code: code.into(),
238 host_id: host_id.into(),
239 resource: resource.into(),
240 status_code: request_info.status_code,
241 request_id: request_info.request_id,
242 ec: ec.into(),
243 key: key.into(),
244 id2: request_info.id2,
245 header: request_info.header,
246 }
247 }
248}
249
250pub struct TosServerError<'a> {
251 message: &'a str,
252 request_url: &'a str,
253 code: &'a str,
254 host_id: &'a str,
255 resource: &'a str,
256 status_code: isize,
257 request_id: &'a str,
258 ec: &'a str,
259 key: &'a str,
260 id2: &'a str,
261 header: &'a HashMap<String, String>,
262}
263
264impl<'a> TosServerError<'a> {
265 pub fn message(&self) -> &'a str {
266 self.message
267 }
268 pub fn code(&self) -> &'a str {
269 self.code
270 }
271 pub fn host_id(&self) -> &'a str {
272 self.host_id
273 }
274 pub fn resource(&self) -> &'a str {
275 self.resource
276 }
277 pub fn status_code(&self) -> isize {
278 self.status_code
279 }
280 pub fn request_id(&self) -> &'a str {
281 self.request_id
282 }
283 pub fn ec(&self) -> &'a str {
284 self.ec
285 }
286 pub fn key(&self) -> &'a str {
287 self.key
288 }
289 pub fn id2(&self) -> &'a str {
290 self.id2
291 }
292 pub fn header(&self) -> &'a HashMap<String, String> {
293 self.header
294 }
295 pub fn request_url(&self) -> &'a str {
296 self.request_url
297 }
298}
299
300#[derive(Deserialize, Debug)]
301pub(crate) struct ErrorResponse {
302 #[serde(default)]
303 #[serde(rename = "Code")]
304 pub(crate) code: String,
305 #[serde(default)]
306 #[serde(rename = "Message")]
307 pub(crate) message: String,
308 #[serde(default)]
309 #[serde(rename = "HostId")]
310 pub(crate) host_id: String,
311 #[serde(default)]
312 #[serde(rename = "Resource")]
313 pub(crate) resource: String,
314 #[serde(default)]
315 #[serde(rename = "EC")]
316 pub(crate) ec: String,
317 #[serde(default)]
318 #[serde(rename = "Key")]
319 pub(crate) key: String,
320 #[serde(default)]
321 #[serde(rename = "canonical_request")]
322 pub(crate) canonical_request: String,
323 #[serde(default)]
324 #[serde(rename = "StringToSign")]
325 pub(crate) string_to_sign: String,
326 #[serde(default)]
327 #[serde(rename = "SignatureProvided")]
328 pub(crate) signature_provided: String,
329}
330
331