bonsaidb_client/
error.rs

1use bonsaidb_core::arc_bytes::serde::Bytes;
2use bonsaidb_core::networking;
3use bonsaidb_core::schema::Name;
4
5/// Errors related to working with the BonsaiDb client.
6#[derive(thiserror::Error, Debug)]
7pub enum Error {
8    #[cfg(feature = "websockets")]
9    /// An error occurred from the WebSocket transport layer.
10    #[error("a transport error occurred: '{0}'")]
11    WebSocket(crate::client::WebSocketError),
12
13    /// An error occurred from networking.
14    #[error("a networking error occurred: '{0}'")]
15    Network(#[from] bonsaidb_core::networking::Error),
16
17    /// An invalid Url was provided.
18    #[error("invalid url: '{0}'")]
19    InvalidUrl(String),
20
21    /// The connection was interrupted.
22    #[error("unexpected disconnection")]
23    Core(#[from] bonsaidb_core::Error),
24
25    /// An error from a `Api`. The actual error is still serialized, as it
26    /// could be any type.
27    #[error("api {name} error")]
28    Api {
29        /// The unique name of the api that responded with an error
30        name: Name,
31        /// The serialized bytes of the error type.
32        error: Bytes,
33    },
34
35    /// The server is incompatible with this version of the client.
36    #[error("server incompatible with client protocol version")]
37    ProtocolVersionMismatch,
38}
39
40impl Error {
41    pub(crate) fn disconnected() -> Self {
42        Self::Core(bonsaidb_core::Error::Networking(
43            networking::Error::Disconnected,
44        ))
45    }
46
47    pub(crate) fn request_timeout() -> Self {
48        Self::Core(bonsaidb_core::Error::Networking(
49            networking::Error::RequestTimeout,
50        ))
51    }
52
53    pub(crate) fn connect_timeout() -> Self {
54        Self::Core(bonsaidb_core::Error::Networking(
55            networking::Error::ConnectTimeout,
56        ))
57    }
58}
59
60impl<T> From<flume::SendError<T>> for Error {
61    fn from(_: flume::SendError<T>) -> Self {
62        Self::disconnected()
63    }
64}
65
66impl From<flume::RecvTimeoutError> for Error {
67    fn from(err: flume::RecvTimeoutError) -> Self {
68        match err {
69            flume::RecvTimeoutError::Timeout => Self::request_timeout(),
70            flume::RecvTimeoutError::Disconnected => Self::disconnected(),
71        }
72    }
73}
74
75impl From<flume::RecvError> for Error {
76    fn from(_: flume::RecvError) -> Self {
77        Self::disconnected()
78    }
79}
80
81impl From<Error> for bonsaidb_core::Error {
82    fn from(other: Error) -> Self {
83        match other {
84            Error::Core(err) => err,
85            other => Self::other("bonsaidb-client", other),
86        }
87    }
88}
89
90#[cfg(feature = "websockets")]
91impl From<bincode::Error> for Error {
92    fn from(other: bincode::Error) -> Self {
93        Self::Core(bonsaidb_core::Error::other("bincode", other))
94    }
95}
96
97#[cfg(not(target_arch = "wasm32"))]
98mod fabruic_impls {
99    macro_rules! impl_from_fabruic {
100        ($error:ty) => {
101            impl From<$error> for $crate::Error {
102                fn from(other: $error) -> Self {
103                    Self::Core(bonsaidb_core::Error::other("quic", other))
104                }
105            }
106        };
107    }
108
109    impl_from_fabruic!(fabruic::error::Sender);
110    impl_from_fabruic!(fabruic::error::Receiver);
111    impl_from_fabruic!(fabruic::error::Stream);
112    impl_from_fabruic!(fabruic::error::Connecting);
113    impl_from_fabruic!(fabruic::error::Connect);
114}
115
116#[cfg(feature = "websockets")]
117impl From<crate::client::WebSocketError> for Error {
118    #[cfg(not(target_arch = "wasm32"))]
119    fn from(err: crate::client::WebSocketError) -> Self {
120        if let crate::client::WebSocketError::Http(response) = &err {
121            if response.status() == 406 {
122                return Self::ProtocolVersionMismatch;
123            }
124        }
125
126        Self::WebSocket(err)
127    }
128
129    #[cfg(target_arch = "wasm32")]
130    fn from(err: crate::client::WebSocketError) -> Self {
131        Self::WebSocket(err)
132    }
133}
134
135impl From<pot::Error> for Error {
136    fn from(err: pot::Error) -> Self {
137        Self::from(bonsaidb_core::Error::from(err))
138    }
139}
140
141/// An error returned from an api request.
142#[derive(thiserror::Error, Debug)]
143pub enum ApiError<T> {
144    /// The API returned its own error type.
145    #[error("api error: {0}")]
146    Api(T),
147    /// An error from BonsaiDb occurred.
148    #[error("client error: {0}")]
149    Client(#[from] Error),
150}
151
152impl From<ApiError<Self>> for bonsaidb_core::Error {
153    fn from(error: ApiError<Self>) -> Self {
154        match error {
155            ApiError::Api(err) => err,
156            ApiError::Client(err) => Self::from(err),
157        }
158    }
159}