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