Skip to main content

xet_client/
error.rs

1use std::num::TryFromIntError;
2
3use anyhow::Error as AnyhowError;
4use http::StatusCode;
5use thiserror::Error;
6use tokio::sync::AcquireError;
7use tokio::sync::mpsc::error::SendError;
8use tokio::task::JoinError;
9use xet_core_structures::merklehash::MerkleHash;
10
11use crate::cas_client::auth::AuthError;
12
13#[non_exhaustive]
14#[derive(Error, Debug)]
15pub enum ClientError {
16    #[error("Format error: {0}")]
17    FormatError(#[from] xet_core_structures::CoreError),
18
19    #[error("Configuration error: {0}")]
20    ConfigurationError(String),
21
22    #[error("Invalid range")]
23    InvalidRange,
24
25    #[error("Invalid arguments")]
26    InvalidArguments,
27
28    #[error("File not found for hash: {0}")]
29    FileNotFound(MerkleHash),
30
31    #[error("IO error: {0}")]
32    IOError(#[from] std::io::Error),
33
34    #[error("Invalid shard key: {0}")]
35    InvalidShardKey(String),
36
37    #[error("Internal error: {0}")]
38    InternalError(AnyhowError),
39
40    #[error("{0}")]
41    Other(String),
42
43    #[error("URL parse error: {0}")]
44    ParseError(#[from] url::ParseError),
45
46    #[error("Request middleware error: {0}")]
47    ReqwestMiddlewareError(#[from] reqwest_middleware::Error),
48
49    #[error("Request error: {0}, domain: {1}")]
50    ReqwestError(reqwest::Error, String),
51
52    #[error("LMDB error: {0}")]
53    ShardDedupDBError(String),
54
55    #[error("CAS object not found for hash: {0}")]
56    XORBNotFound(MerkleHash),
57
58    #[error("Presigned URL expired")]
59    PresignedUrlExpirationError,
60
61    #[error("Cloned error: {0}")]
62    Cloned(String),
63
64    #[error("Auth error: {0}")]
65    AuthError(#[from] AuthError),
66
67    #[error("Credential helper error: {0}")]
68    CredentialHelper(AnyhowError),
69
70    #[error("Invalid repo type: {0}")]
71    InvalidRepoType(String),
72
73    #[error("Invalid key: {0}")]
74    InvalidKey(String),
75
76    #[error("Cache error: {0}")]
77    CacheError(String),
78}
79
80impl Clone for ClientError {
81    fn clone(&self) -> Self {
82        match self {
83            ClientError::Cloned(s) => ClientError::Cloned(s.clone()),
84            other => ClientError::Cloned(format!("{other:?}")),
85        }
86    }
87}
88
89impl From<reqwest::Error> for ClientError {
90    fn from(mut value: reqwest::Error) -> Self {
91        let url = if let Some(url) = value.url_mut() {
92            url.set_query(None);
93            url.to_string()
94        } else {
95            "no-url".to_string()
96        };
97        let value = value.without_url();
98        ClientError::ReqwestError(value, url)
99    }
100}
101
102impl ClientError {
103    pub fn internal(value: impl std::error::Error + Send + Sync + 'static) -> Self {
104        ClientError::InternalError(AnyhowError::new(value))
105    }
106
107    pub fn credential_helper_error(e: impl std::error::Error + Send + Sync + 'static) -> Self {
108        ClientError::CredentialHelper(AnyhowError::new(e))
109    }
110
111    pub fn status(&self) -> Option<StatusCode> {
112        match self {
113            ClientError::ReqwestMiddlewareError(e) => e.status(),
114            ClientError::ReqwestError(e, _) => e.status(),
115            _ => None,
116        }
117    }
118}
119
120pub type Result<T> = std::result::Result<T, ClientError>;
121
122impl PartialEq for ClientError {
123    fn eq(&self, other: &ClientError) -> bool {
124        match (self, other) {
125            (ClientError::XORBNotFound(a), ClientError::XORBNotFound(b)) => a == b,
126            (e1, e2) => std::mem::discriminant(e1) == std::mem::discriminant(e2),
127        }
128    }
129}
130
131#[cfg(not(target_family = "wasm"))]
132impl From<xet_runtime::utils::singleflight::SingleflightError<ClientError>> for ClientError {
133    fn from(value: xet_runtime::utils::singleflight::SingleflightError<ClientError>) -> Self {
134        match value {
135            xet_runtime::utils::singleflight::SingleflightError::InternalError(e) => e,
136            e => ClientError::Other(format!("single flight error: {e}")),
137        }
138    }
139}
140
141impl<T: Send + Sync + 'static> From<std::sync::PoisonError<T>> for ClientError {
142    fn from(value: std::sync::PoisonError<T>) -> Self {
143        Self::internal(value)
144    }
145}
146
147impl From<AcquireError> for ClientError {
148    fn from(value: AcquireError) -> Self {
149        Self::internal(value)
150    }
151}
152
153impl<T: Send + Sync + 'static> From<SendError<T>> for ClientError {
154    fn from(value: SendError<T>) -> Self {
155        Self::internal(value)
156    }
157}
158
159impl From<JoinError> for ClientError {
160    fn from(value: JoinError) -> Self {
161        Self::internal(value)
162    }
163}
164
165impl From<TryFromIntError> for ClientError {
166    fn from(value: TryFromIntError) -> Self {
167        Self::internal(value)
168    }
169}
170
171impl From<crate::chunk_cache::error::ChunkCacheError> for ClientError {
172    fn from(e: crate::chunk_cache::error::ChunkCacheError) -> Self {
173        ClientError::CacheError(e.to_string())
174    }
175}
176
177impl From<xet_runtime::error::RuntimeError> for ClientError {
178    fn from(e: xet_runtime::error::RuntimeError) -> Self {
179        ClientError::internal(e)
180    }
181}