1use http::{Method, StatusCode};
20use std::error::Error as StdError;
21use std::fmt::{Display, Formatter};
22
23pub type Result<T> = std::result::Result<T, Error>;
24
25#[derive(Debug, PartialEq)]
26pub struct Error {
27 inner: Box<ErrorImpl>,
28}
29
30impl Display for Error {
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 write!(f, "{}", self.inner.kind)
33 }
34}
35
36impl StdError for Error {}
37
38impl Error {
39 pub(crate) fn new_message_error(msg: impl Into<String>) -> Self {
40 Self {
41 inner: Box::new(ErrorImpl {
42 kind: ErrorKind::Message(msg.into()),
43 }),
44 }
45 }
46
47 pub(crate) fn new_invalid_argument_error(
48 msg: impl Into<String>,
49 arg: impl Into<Option<String>>,
50 ) -> Self {
51 Self {
52 inner: Box::new(ErrorImpl {
53 kind: ErrorKind::InvalidArgument {
54 msg: msg.into(),
55 arg: arg.into(),
56 },
57 }),
58 }
59 }
60
61 pub fn kind(&self) -> &ErrorKind {
62 &self.inner.kind
63 }
64}
65
66#[derive(Debug)]
67pub struct ErrorImpl {
68 pub kind: ErrorKind,
69}
70
71impl PartialEq for ErrorImpl {
72 fn eq(&self, other: &Self) -> bool {
73 self.kind == other.kind
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78#[non_exhaustive]
79pub enum ErrorKind {
80 Server(ServerError),
81 Resource(ResourceError),
82 #[non_exhaustive]
83 InvalidArgument {
84 msg: String,
85 arg: Option<String>,
86 },
87 Message(String),
88}
89
90impl Display for ErrorKind {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 match self {
93 ErrorKind::Server(e) => write!(f, "server error: {e}"),
94 ErrorKind::Resource(e) => write!(f, "resource error: {e}"),
95 ErrorKind::InvalidArgument { msg, arg } => {
96 if let Some(arg) = arg {
97 write!(f, "invalid argument: {msg}: {arg}")
98 } else {
99 write!(f, "invalid argument: {msg}")
100 }
101 }
102 ErrorKind::Message(msg) => write!(f, "{msg}"),
103 }
104 }
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub struct ServerError {
109 status_code: StatusCode,
110 url: String,
111 body: String,
112 method: Method,
113 path: String,
114 kind: ServerErrorKind,
115}
116
117impl StdError for ServerError {}
118
119impl Display for ServerError {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 write!(
122 f,
123 "server error: method: {}, path: {} status code: {}, body: {}, kind: {}",
124 self.method, self.path, self.status_code, self.body, self.kind
125 )
126 }
127}
128
129impl ServerError {
130 pub(crate) fn new(
131 status_code: StatusCode,
132 url: String,
133 method: Method,
134 path: String,
135 body: String,
136 kind: ServerErrorKind,
137 ) -> Self {
138 Self {
139 status_code,
140 url,
141 method,
142 path,
143 body,
144 kind,
145 }
146 }
147
148 pub fn kind(&self) -> &ServerErrorKind {
149 &self.kind
150 }
151
152 pub fn status_code(&self) -> StatusCode {
153 self.status_code
154 }
155
156 pub fn body(&self) -> &str {
157 &self.body
158 }
159
160 pub fn path(&self) -> &str {
161 &self.path
162 }
163
164 pub fn method(&self) -> &Method {
165 &self.method
166 }
167
168 pub fn url(&self) -> &str {
169 &self.url
170 }
171}
172
173#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
174#[non_exhaustive]
175pub enum ServerErrorKind {
176 AccessDenied,
177 UnsupportedFeature { feature: String },
178 ScopeExists,
179 ScopeNotFound,
180 CollectionExists,
181 CollectionNotFound,
182 BucketExists,
183 BucketNotFound,
184 FlushDisabled,
185 ServerInvalidArg { arg: String, reason: String },
186 BucketUuidMismatch,
187 UserNotFound,
188 GroupNotFound,
189 OperationDelayed,
190 Unknown,
191}
192
193impl Display for ServerErrorKind {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 match self {
196 ServerErrorKind::AccessDenied => write!(f, "access denied"),
197 ServerErrorKind::UnsupportedFeature { feature } => {
198 write!(f, "unsupported feature {feature}")
199 }
200 ServerErrorKind::ScopeExists => write!(f, "scope exists"),
201 ServerErrorKind::ScopeNotFound => write!(f, "scope not found"),
202 ServerErrorKind::CollectionExists => write!(f, "collection exists"),
203 ServerErrorKind::CollectionNotFound => write!(f, "collection not found"),
204 ServerErrorKind::BucketExists => write!(f, "bucket exists"),
205 ServerErrorKind::BucketNotFound => write!(f, "bucket not found"),
206 ServerErrorKind::FlushDisabled => write!(f, "flush disabled"),
207 ServerErrorKind::ServerInvalidArg { arg, reason } => {
208 write!(f, "server invalid argument: {arg} - {reason}")
209 }
210 ServerErrorKind::BucketUuidMismatch => write!(f, "bucket uuid mismatch"),
211 ServerErrorKind::UserNotFound => write!(f, "user not found"),
212 ServerErrorKind::GroupNotFound => write!(f, "group not found"),
213 ServerErrorKind::OperationDelayed => {
214 write!(f, "operation was delayed, but will continue")
215 }
216 ServerErrorKind::Unknown => write!(f, "unknown error"),
217 }
218 }
219}
220
221#[derive(Debug, Clone, PartialEq, Eq)]
222pub struct ResourceError {
223 cause: ServerError,
224 scope_name: String,
225 collection_name: String,
226 bucket_name: String,
227}
228
229impl StdError for ResourceError {}
230
231impl Display for ResourceError {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 write!(
234 f,
235 "resource error: scope: {}, collection: {}, bucket: {}, cause: {}",
236 self.scope_name, self.collection_name, self.bucket_name, self.cause
237 )
238 }
239}
240
241impl ResourceError {
242 pub(crate) fn new(
243 cause: ServerError,
244 bucket_name: impl Into<String>,
245 scope_name: impl Into<String>,
246 collection_name: impl Into<String>,
247 ) -> Self {
248 Self {
249 cause,
250 bucket_name: bucket_name.into(),
251 scope_name: scope_name.into(),
252 collection_name: collection_name.into(),
253 }
254 }
255
256 pub fn cause(&self) -> &ServerError {
257 &self.cause
258 }
259
260 pub fn bucket_name(&self) -> &str {
261 &self.bucket_name
262 }
263
264 pub fn scope_name(&self) -> &str {
265 &self.scope_name
266 }
267
268 pub fn collection_name(&self) -> &str {
269 &self.collection_name
270 }
271}
272
273impl<E> From<E> for Error
274where
275 ErrorKind: From<E>,
276{
277 fn from(err: E) -> Self {
278 Self {
279 inner: Box::new(ErrorImpl {
280 kind: ErrorKind::from(err),
281 }),
282 }
283 }
284}
285
286impl From<ServerError> for Error {
287 fn from(value: ServerError) -> Self {
288 Self {
289 inner: Box::new(ErrorImpl {
290 kind: ErrorKind::Server(value),
291 }),
292 }
293 }
294}
295
296impl From<ResourceError> for Error {
297 fn from(value: ResourceError) -> Self {
298 Self {
299 inner: Box::new(ErrorImpl {
300 kind: ErrorKind::Resource(value),
301 }),
302 }
303 }
304}