Lines
46.34 %
Functions
39.42 %
Branches
100 %
use std::convert::Infallible;
use std::fmt::Debug;
use async_trait::async_trait;
use bonsaidb_core::connection::Session;
use bonsaidb_core::permissions::PermissionDenied;
use bonsaidb_core::schema::{InsertError, InvalidNameError};
use crate::server::ConnectedClient;
use crate::{CustomServer, Error, ServerConfiguration};
/// Tailors the behavior of a server to your needs.
#[async_trait]
pub trait Backend: Debug + Send + Sync + Sized + 'static {
/// The error type that can be returned from the backend functions. If a
/// backend doesn't need an error type, [`Infallible`] can be used.
type Error: std::error::Error + Send + Sync;
/// The type of data that can be stored in
/// [`ConnectedClient::set_client_data`]. This allows state to be stored
/// associated with each connected client.
type ClientData: Send + Sync + Debug;
/// Invoked once before the server is initialized.
#[allow(unused_variables)]
fn configure(
config: ServerConfiguration<Self>,
) -> Result<ServerConfiguration<Self>, BackendError<Self::Error>> {
Ok(config)
}
/// Invoked once after initialization during
/// [`Server::open`/`CustomServer::open`](CustomServer::open).
async fn initialize(
&self,
server: &CustomServer<Self>,
) -> Result<(), BackendError<Self::Error>> {
Ok(())
/// A client disconnected from the server. This is invoked before authentication has been performed.
#[must_use]
async fn client_connected(
client: &ConnectedClient<Self>,
) -> Result<ConnectionHandling, BackendError<Self::Error>> {
log::info!(
"{:?} client connected from {:?}",
client.transport(),
client.address()
);
Ok(ConnectionHandling::Accept)
/// A client disconnected from the server.
async fn client_disconnected(
client: ConnectedClient<Self>,
"{:?} client disconnected ({:?})",
/// A client successfully authenticated.
async fn client_authenticated(
session: &Session,
"{:?} client authenticated as user: {:?}",
session.authentication
/// A client's session has ended.
///
/// If `disconnecting` is true, the session is ending because the client is
/// in the process of disconnecting.
async fn client_session_ended(
session: Session,
disconnecting: bool,
"{:?} client session ended {:?}",
/// A [`Backend`] with no custom functionality.
#[derive(Debug, Default)]
pub struct NoBackend;
impl Backend for NoBackend {
type ClientData = ();
type Error = Infallible;
/// Controls how a server should handle a connection.
pub enum ConnectionHandling {
/// The server should accept this connection.
Accept,
/// The server should reject this connection.
Reject,
/// An error that can occur inside of a [`Backend`] function.
#[derive(thiserror::Error, Debug)]
pub enum BackendError<E = Infallible> {
/// A backend-related error.
#[error("backend error: {0}")]
Backend(E),
/// A server-related error.
#[error("server error: {0}")]
Server(#[from] Error),
impl<E> From<PermissionDenied> for BackendError<E> {
fn from(permission_denied: PermissionDenied) -> Self {
Self::Server(Error::from(permission_denied))
impl<E> From<bonsaidb_core::Error> for BackendError<E> {
fn from(err: bonsaidb_core::Error) -> Self {
Self::Server(Error::from(err))
impl<E> From<bonsaidb_local::Error> for BackendError<E> {
fn from(err: bonsaidb_local::Error) -> Self {
impl<E> From<std::io::Error> for BackendError<E> {
fn from(err: std::io::Error) -> Self {
impl<E> From<InvalidNameError> for BackendError<E> {
fn from(err: InvalidNameError) -> Self {
#[cfg(feature = "websockets")]
impl<E> From<bincode::Error> for BackendError<E> {
fn from(other: bincode::Error) -> Self {
Self::Server(Error::from(bonsaidb_local::Error::from(other)))
impl<E> From<pot::Error> for BackendError<E> {
fn from(other: pot::Error) -> Self {
impl<T, E> From<InsertError<T>> for BackendError<E> {
fn from(error: InsertError<T>) -> Self {
Self::Server(Error::from(error.error))