bonsaidb_server/
backend.rs

1use std::convert::Infallible;
2use std::fmt::Debug;
3
4use async_trait::async_trait;
5use bonsaidb_core::connection::Session;
6use bonsaidb_core::permissions::PermissionDenied;
7use bonsaidb_core::schema::{InsertError, InvalidNameError};
8
9use crate::server::ConnectedClient;
10use crate::{CustomServer, Error, ServerConfiguration};
11
12/// Tailors the behavior of a server to your needs.
13#[async_trait]
14pub trait Backend: Debug + Send + Sync + Sized + 'static {
15    /// The error type that can be returned from the backend functions. If a
16    /// backend doesn't need an error type, [`Infallible`] can be used.
17    type Error: std::error::Error + Send + Sync;
18    /// The type of data that can be stored in
19    /// [`ConnectedClient::set_client_data`]. This allows state to be stored
20    /// associated with each connected client.
21    type ClientData: Send + Sync + Debug;
22
23    /// Invoked once before the server is initialized.
24    #[allow(unused_variables)]
25    fn configure(
26        config: ServerConfiguration<Self>,
27    ) -> Result<ServerConfiguration<Self>, BackendError<Self::Error>> {
28        Ok(config)
29    }
30
31    /// Invoked once after initialization during
32    /// [`Server::open`/`CustomServer::open`](CustomServer::open).
33    #[allow(unused_variables)]
34    async fn initialize(
35        &self,
36        server: &CustomServer<Self>,
37    ) -> Result<(), BackendError<Self::Error>> {
38        Ok(())
39    }
40
41    /// A client disconnected from the server. This is invoked before authentication has been performed.
42    #[allow(unused_variables)]
43    #[must_use]
44    async fn client_connected(
45        &self,
46        client: &ConnectedClient<Self>,
47        server: &CustomServer<Self>,
48    ) -> Result<ConnectionHandling, BackendError<Self::Error>> {
49        log::info!(
50            "{:?} client connected from {:?}",
51            client.transport(),
52            client.address()
53        );
54
55        Ok(ConnectionHandling::Accept)
56    }
57
58    /// A client disconnected from the server.
59    #[allow(unused_variables)]
60    async fn client_disconnected(
61        &self,
62        client: ConnectedClient<Self>,
63        server: &CustomServer<Self>,
64    ) -> Result<(), BackendError<Self::Error>> {
65        log::info!(
66            "{:?} client disconnected ({:?})",
67            client.transport(),
68            client.address()
69        );
70        Ok(())
71    }
72
73    /// A client successfully authenticated.
74    #[allow(unused_variables)]
75    async fn client_authenticated(
76        &self,
77        client: ConnectedClient<Self>,
78        session: &Session,
79        server: &CustomServer<Self>,
80    ) -> Result<(), BackendError<Self::Error>> {
81        log::info!(
82            "{:?} client authenticated as user: {:?}",
83            client.transport(),
84            session.authentication
85        );
86        Ok(())
87    }
88
89    /// A client's session has ended.
90    ///
91    /// If `disconnecting` is true, the session is ending because the client is
92    /// in the process of disconnecting.
93    #[allow(unused_variables)]
94    async fn client_session_ended(
95        &self,
96        session: Session,
97        client: &ConnectedClient<Self>,
98        disconnecting: bool,
99        server: &CustomServer<Self>,
100    ) -> Result<(), BackendError<Self::Error>> {
101        log::info!(
102            "{:?} client session ended {:?}",
103            client.transport(),
104            session.authentication
105        );
106        Ok(())
107    }
108}
109
110/// A [`Backend`] with no custom functionality.
111#[derive(Debug, Default)]
112pub struct NoBackend;
113
114impl Backend for NoBackend {
115    type ClientData = ();
116    type Error = Infallible;
117}
118
119/// Controls how a server should handle a connection.
120pub enum ConnectionHandling {
121    /// The server should accept this connection.
122    Accept,
123    /// The server should reject this connection.
124    Reject,
125}
126
127/// An error that can occur inside of a [`Backend`] function.
128#[derive(thiserror::Error, Debug)]
129pub enum BackendError<E = Infallible> {
130    /// A backend-related error.
131    #[error("backend error: {0}")]
132    Backend(E),
133    /// A server-related error.
134    #[error("server error: {0}")]
135    Server(#[from] Error),
136}
137
138impl<E> From<PermissionDenied> for BackendError<E> {
139    fn from(permission_denied: PermissionDenied) -> Self {
140        Self::Server(Error::from(permission_denied))
141    }
142}
143
144impl<E> From<bonsaidb_core::Error> for BackendError<E> {
145    fn from(err: bonsaidb_core::Error) -> Self {
146        Self::Server(Error::from(err))
147    }
148}
149
150impl<E> From<bonsaidb_local::Error> for BackendError<E> {
151    fn from(err: bonsaidb_local::Error) -> Self {
152        Self::Server(Error::from(err))
153    }
154}
155
156impl<E> From<std::io::Error> for BackendError<E> {
157    fn from(err: std::io::Error) -> Self {
158        Self::Server(Error::from(err))
159    }
160}
161
162impl<E> From<InvalidNameError> for BackendError<E> {
163    fn from(err: InvalidNameError) -> Self {
164        Self::Server(Error::from(err))
165    }
166}
167
168#[cfg(feature = "websockets")]
169impl<E> From<bincode::Error> for BackendError<E> {
170    fn from(other: bincode::Error) -> Self {
171        Self::Server(Error::from(bonsaidb_local::Error::from(other)))
172    }
173}
174
175impl<E> From<pot::Error> for BackendError<E> {
176    fn from(other: pot::Error) -> Self {
177        Self::Server(Error::from(bonsaidb_local::Error::from(other)))
178    }
179}
180
181impl<T, E> From<InsertError<T>> for BackendError<E> {
182    fn from(error: InsertError<T>) -> Self {
183        Self::Server(Error::from(error.error))
184    }
185}