Skip to main content

ve_tos_rust_sdk/
error.rs

1/*
2 * Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16use 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