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}