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}