1
use bonsaidb_core::arc_bytes::serde::Bytes;
2
use bonsaidb_core::networking;
3
use bonsaidb_core::schema::Name;
4

            
5
/// Errors related to working with the BonsaiDb client.
6
792
#[derive(thiserror::Error, Debug)]
7
pub 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

            
40
impl Error {
41
1710
    pub(crate) fn disconnected() -> Self {
42
1710
        Self::Core(bonsaidb_core::Error::Networking(
43
1710
            networking::Error::Disconnected,
44
1710
        ))
45
1710
    }
46

            
47
72
    pub(crate) fn request_timeout() -> Self {
48
72
        Self::Core(bonsaidb_core::Error::Networking(
49
72
            networking::Error::RequestTimeout,
50
72
        ))
51
72
    }
52

            
53
72
    pub(crate) fn connect_timeout() -> Self {
54
72
        Self::Core(bonsaidb_core::Error::Networking(
55
72
            networking::Error::ConnectTimeout,
56
72
        ))
57
72
    }
58
}
59

            
60
impl<T> From<flume::SendError<T>> for Error {
61
    fn from(_: flume::SendError<T>) -> Self {
62
        Self::disconnected()
63
    }
64
}
65

            
66
impl From<flume::RecvTimeoutError> for Error {
67
36
    fn from(err: flume::RecvTimeoutError) -> Self {
68
36
        match err {
69
36
            flume::RecvTimeoutError::Timeout => Self::request_timeout(),
70
            flume::RecvTimeoutError::Disconnected => Self::disconnected(),
71
        }
72
36
    }
73
}
74

            
75
impl From<flume::RecvError> for Error {
76
    fn from(_: flume::RecvError) -> Self {
77
        Self::disconnected()
78
    }
79
}
80

            
81
impl From<Error> for bonsaidb_core::Error {
82
10206
    fn from(other: Error) -> Self {
83
10206
        match other {
84
10152
            Error::Core(err) => err,
85
54
            other => Self::other("bonsaidb-client", other),
86
        }
87
10206
    }
88
}
89

            
90
#[cfg(feature = "websockets")]
91
impl 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"))]
98
mod fabruic_impls {
99
    macro_rules! impl_from_fabruic {
100
        ($error:ty) => {
101
            impl From<$error> for $crate::Error {
102
180
                fn from(other: $error) -> Self {
103
180
                    Self::Core(bonsaidb_core::Error::other("quic", other))
104
180
                }
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")]
117
impl From<crate::client::WebSocketError> for Error {
118
    #[cfg(not(target_arch = "wasm32"))]
119
    fn from(err: crate::client::WebSocketError) -> Self {
120
36
        if let crate::client::WebSocketError::Http(response) = &err {
121
18
            if response.status() == 406 {
122
18
                return Self::ProtocolVersionMismatch;
123
            }
124
18
        }
125

            
126
18
        Self::WebSocket(err)
127
36
    }
128

            
129
    #[cfg(target_arch = "wasm32")]
130
    fn from(err: crate::client::WebSocketError) -> Self {
131
        Self::WebSocket(err)
132
    }
133
}
134

            
135
impl 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)]
143
pub 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

            
152
impl From<ApiError<Self>> for bonsaidb_core::Error {
153
10206
    fn from(error: ApiError<Self>) -> Self {
154
10206
        match error {
155
            ApiError::Api(err) => err,
156
10206
            ApiError::Client(err) => Self::from(err),
157
        }
158
10206
    }
159
}