opendal/services/dropbox/
error.rs1use http::Response;
19use http::StatusCode;
20use serde::Deserialize;
21
22use crate::raw::*;
23use crate::*;
24
25#[derive(Default, Debug, Deserialize)]
26#[serde(default)]
27pub struct DropboxErrorResponse {
28 pub error_summary: String,
29}
30
31pub(super) fn parse_error(resp: Response<Buffer>) -> Error {
33 let (parts, body) = resp.into_parts();
34 let bs = body.to_bytes();
35
36 let (mut kind, mut retryable) = match parts.status {
37 StatusCode::NOT_FOUND => (ErrorKind::NotFound, false),
38 StatusCode::FORBIDDEN => (ErrorKind::PermissionDenied, false),
39 StatusCode::TOO_MANY_REQUESTS => (ErrorKind::RateLimited, true),
40 StatusCode::INTERNAL_SERVER_ERROR
41 | StatusCode::BAD_GATEWAY
42 | StatusCode::SERVICE_UNAVAILABLE
43 | StatusCode::GATEWAY_TIMEOUT => (ErrorKind::Unexpected, true),
44 _ => (ErrorKind::Unexpected, false),
45 };
46
47 let (message, dropbox_err) = serde_json::from_slice::<DropboxErrorResponse>(&bs)
48 .map(|dropbox_err| (format!("{dropbox_err:?}"), Some(dropbox_err)))
49 .unwrap_or_else(|_| (String::from_utf8_lossy(&bs).into_owned(), None));
50
51 if let Some(dropbox_err) = dropbox_err {
52 (kind, retryable) =
53 parse_dropbox_error_summary(&dropbox_err.error_summary).unwrap_or((kind, retryable));
54 }
55
56 let mut err = Error::new(kind, message);
57
58 err = with_error_response_context(err, parts);
59
60 if retryable {
61 err = err.set_temporary();
62 }
63
64 err
65}
66
67pub fn parse_dropbox_error_summary(summary: &str) -> Option<(ErrorKind, bool)> {
73 if summary.starts_with("path/not_found")
74 || summary.starts_with("path_lookup/not_found")
75 || summary.starts_with("from_lookup/not_found")
76 {
77 Some((ErrorKind::NotFound, false))
78 } else if summary.starts_with("path/conflict") {
79 Some((ErrorKind::AlreadyExists, false))
80 } else if summary.starts_with("too_many_write_operations") {
81 Some((ErrorKind::RateLimited, true))
82 } else {
83 None
84 }
85}