jotta_fs/
errors.rs

1//! Nobody is perfect.
2use thiserror::Error;
3
4use crate::api::{Exception, JsonErrorBody, MaybeUnknown, XmlErrorBody};
5
6/// Error used by the entire Jotta crate.
7#[derive(Debug, Error)]
8pub enum Error {
9    /// HTTP error.
10    #[error("{0}")]
11    HttpError(#[from] reqwest::Error),
12
13    /// Url error.
14    #[error("invalid url")]
15    UrlError(#[from] url::ParseError),
16
17    /// Upstream (unrecongnized) Jottacloud error. Might be due to
18    /// a user error.
19    #[error("jotta error")]
20    JottaError(ApiResError),
21
22    /// XML deserialization error.
23    #[error("xml error: {0}")]
24    XmlError(#[from] serde_xml_rs::Error),
25
26    /// File conflict.
27    #[error("file or folder already exists")]
28    AlreadyExists,
29
30    /// Bad credentials.
31    #[error("bad credentials")]
32    BadCredentials,
33
34    /// Not found.
35    #[error("file or folder does not exist")]
36    NoSuchFileOrFolder,
37
38    /// Incomplete upload.
39    #[error("incomplete upload; maybe too short body?")]
40    IncompleteUpload,
41
42    /// Invalid argument.
43    #[error("invalid argument")]
44    InvalidArgument,
45
46    /// Corrupt upload, probably due to a checksum mismatch.
47    #[error("corrupt upload")]
48    CorruptUpload,
49
50    /// Token was not successfully renewed.
51    #[error("token renewal failed")]
52    TokenRenewalFailed,
53
54    /// Range not satisfiable.
55    #[error("range not satisfiable")]
56    RangeNotSatisfiable,
57}
58
59/// All possible errors returned by the upstream Jottacloud API.
60#[derive(Debug)]
61pub enum ApiResError {
62    /// JSON error, returned by `api.jottacloud.com/files/v1` for example.
63    Json(JsonErrorBody),
64    /// XML error returned by `jfs.jottacloud.com`.
65    Xml(XmlErrorBody),
66}
67
68impl From<JsonErrorBody> for Error {
69    fn from(err: JsonErrorBody) -> Self {
70        match err.error_id {
71            Some(MaybeUnknown::Known(exception)) => Error::from(exception),
72            _ => Self::JottaError(ApiResError::Json(err)),
73        }
74    }
75}
76
77impl From<XmlErrorBody> for Error {
78    fn from(err: XmlErrorBody) -> Self {
79        if let Some(exception) = err.exception_opt() {
80            Error::from(exception)
81        } else {
82            Self::JottaError(ApiResError::Xml(err))
83        }
84    }
85}
86
87impl From<Exception> for Error {
88    fn from(exception: Exception) -> Self {
89        match exception {
90            Exception::UniqueFileException => Error::AlreadyExists,
91            Exception::BadCredentialsException => Error::BadCredentials,
92            Exception::CorruptUploadOpenApiException => Error::CorruptUpload,
93            Exception::NoSuchFileException | Exception::NoSuchPathException => {
94                Error::NoSuchFileOrFolder
95            }
96            Exception::InvalidArgumentException => Error::InvalidArgument,
97            Exception::IncompleteUploadOpenApiException => Error::IncompleteUpload,
98            Exception::RequestedRangeNotSatisfiedException => Error::RangeNotSatisfiable,
99        }
100    }
101}