1
use std::{convert::Infallible, fmt::Debug};
2

            
3
use async_trait::async_trait;
4
use bonsaidb_core::{
5
    connection::Session,
6
    permissions::PermissionDenied,
7
    schema::{InsertError, InvalidNameError},
8
};
9

            
10
use crate::{server::ConnectedClient, CustomServer, Error, ServerConfiguration};
11

            
12
/// Tailors the behavior of a server to your needs.
13
#[async_trait]
14
pub 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
82
    fn configure(
26
82
        config: ServerConfiguration<Self>,
27
82
    ) -> Result<ServerConfiguration<Self>, BackendError<Self::Error>> {
28
82
        Ok(config)
29
82
    }
30

            
31
    /// Invoked once after initialization during
32
    /// [`Server::open`/`CustomServer::open`](CustomServer::open).
33
    #[allow(unused_variables)]
34
76
    async fn initialize(server: &CustomServer<Self>) -> Result<(), BackendError<Self::Error>> {
35
76
        Ok(())
36
76
    }
37

            
38
    /// A client disconnected from the server. This is invoked before authentication has been performed.
39
    #[allow(unused_variables)]
40
    #[must_use]
41
147
    async fn client_connected(
42
147
        client: &ConnectedClient<Self>,
43
147
        server: &CustomServer<Self>,
44
147
    ) -> Result<ConnectionHandling, BackendError<Self::Error>> {
45
147
        log::info!(
46
            "{:?} client connected from {:?}",
47
            client.transport(),
48
            client.address()
49
        );
50

            
51
147
        Ok(ConnectionHandling::Accept)
52
294
    }
53

            
54
    /// A client disconnected from the server.
55
    #[allow(unused_variables)]
56
86
    async fn client_disconnected(
57
86
        client: ConnectedClient<Self>,
58
86
        server: &CustomServer<Self>,
59
86
    ) -> Result<(), BackendError<Self::Error>> {
60
86
        log::info!(
61
            "{:?} client disconnected ({:?})",
62
            client.transport(),
63
            client.address()
64
        );
65
86
        Ok(())
66
172
    }
67

            
68
    /// A client successfully authenticated.
69
    #[allow(unused_variables)]
70
    async fn client_authenticated(
71
        client: ConnectedClient<Self>,
72
        session: &Session,
73
        server: &CustomServer<Self>,
74
    ) -> Result<(), BackendError<Self::Error>> {
75
        log::info!(
76
            "{:?} client authenticated as user: {:?}",
77
            client.transport(),
78
            session.identity
79
        );
80
        Ok(())
81
    }
82
}
83

            
84
/// A [`Backend`] with no custom functionality.
85
#[cfg_attr(feature = "cli", derive(clap::Subcommand))]
86
#[derive(Debug)]
87
pub enum NoBackend {}
88

            
89
impl Backend for NoBackend {
90
    type Error = Infallible;
91
    type ClientData = ();
92
}
93

            
94
/// Controls how a server should handle a connection.
95
pub enum ConnectionHandling {
96
    /// The server should accept this connection.
97
    Accept,
98
    /// The server should reject this connection.
99
    Reject,
100
}
101

            
102
/// An error that can occur inside of a [`Backend`] function.
103
#[derive(thiserror::Error, Debug)]
104
pub enum BackendError<E = Infallible> {
105
    /// A backend-related error.
106
    #[error("backend error: {0}")]
107
    Backend(E),
108
    /// A server-related error.
109
    #[error("server error: {0}")]
110
    Server(#[from] Error),
111
}
112

            
113
impl<E> From<PermissionDenied> for BackendError<E> {
114
    fn from(permission_denied: PermissionDenied) -> Self {
115
        Self::Server(Error::from(permission_denied))
116
    }
117
}
118

            
119
impl<E> From<bonsaidb_core::Error> for BackendError<E> {
120
    fn from(err: bonsaidb_core::Error) -> Self {
121
        Self::Server(Error::from(err))
122
    }
123
}
124

            
125
impl<E> From<bonsaidb_local::Error> for BackendError<E> {
126
    fn from(err: bonsaidb_local::Error) -> Self {
127
        Self::Server(Error::from(err))
128
    }
129
}
130

            
131
impl<E> From<std::io::Error> for BackendError<E> {
132
    fn from(err: std::io::Error) -> Self {
133
        Self::Server(Error::from(err))
134
    }
135
}
136

            
137
impl<E> From<InvalidNameError> for BackendError<E> {
138
    fn from(err: InvalidNameError) -> Self {
139
        Self::Server(Error::from(err))
140
    }
141
}
142

            
143
#[cfg(feature = "websockets")]
144
impl<E> From<bincode::Error> for BackendError<E> {
145
    fn from(other: bincode::Error) -> Self {
146
        Self::Server(Error::from(bonsaidb_local::Error::from(other)))
147
    }
148
}
149

            
150
impl<E> From<pot::Error> for BackendError<E> {
151
    fn from(other: pot::Error) -> Self {
152
        Self::Server(Error::from(bonsaidb_local::Error::from(other)))
153
    }
154
}
155

            
156
impl<T, E> From<InsertError<T>> for BackendError<E> {
157
    fn from(error: InsertError<T>) -> Self {
158
        Self::Server(Error::from(error.error))
159
    }
160
}