use std::collections::HashMap;
use std::marker::PhantomData;
use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
use std::path::Path;
use std::sync::Arc;
use bonsaidb_core::api;
use bonsaidb_core::api::ApiName;
#[cfg(feature = "encryption")]
use bonsaidb_core::document::KeyId;
use bonsaidb_core::permissions::{Permissions, Statement};
use bonsaidb_core::schema::Schema;
#[cfg(feature = "compression")]
use bonsaidb_local::config::Compression;
use bonsaidb_local::config::{Builder, KeyValuePersistence, StorageConfiguration};
#[cfg(feature = "encryption")]
use bonsaidb_local::vault::AnyVaultKeyStorage;
use crate::api::{AnyHandler, AnyWrapper, Handler};
use crate::{Backend, Error, NoBackend};
#[derive(Debug, Clone)]
#[must_use]
#[non_exhaustive]
pub struct ServerConfiguration<B: Backend = NoBackend> {
pub backend: B,
pub server_name: String,
pub client_simultaneous_request_limit: usize,
pub request_workers: usize,
pub storage: StorageConfiguration,
pub default_permissions: DefaultPermissions,
#[cfg(feature = "acme")]
pub acme: AcmeConfiguration,
pub(crate) custom_apis: HashMap<ApiName, Arc<dyn AnyHandler<B>>>,
}
impl<B: Backend> ServerConfiguration<B> {
pub fn default_for(backend: B) -> Self {
Self {
backend,
server_name: String::from("bonsaidb"),
client_simultaneous_request_limit: 16,
request_workers: 16,
storage: bonsaidb_local::config::StorageConfiguration::default(),
default_permissions: DefaultPermissions::Permissions(Permissions::default()),
custom_apis: HashMap::default(),
#[cfg(feature = "acme")]
acme: AcmeConfiguration::default(),
}
}
pub fn new_with_backend<P: AsRef<Path>>(path: P, backend: B) -> Self {
Self::default_for(backend).path(path)
}
pub fn server_name(mut self, server_name: impl Into<String>) -> Self {
self.server_name = server_name.into();
self
}
pub const fn client_simultaneous_request_limit(mut self, request_limit: usize) -> Self {
self.client_simultaneous_request_limit = request_limit;
self
}
pub const fn request_workers(mut self, workers: usize) -> Self {
self.request_workers = workers;
self
}
pub fn default_permissions<P: Into<DefaultPermissions>>(
mut self,
default_permissions: P,
) -> Self {
self.default_permissions = default_permissions.into();
self
}
#[cfg(feature = "acme")]
pub fn acme_contact_email(mut self, contact_email: impl Into<String>) -> Self {
self.acme.contact_email = Some(contact_email.into());
self
}
#[cfg(feature = "acme")]
pub fn acme_directory(mut self, directory: impl Into<String>) -> Self {
self.acme.directory = directory.into();
self
}
pub fn register_custom_api<Dispatcher: Handler<Api, B> + 'static, Api: api::Api>(
&mut self,
) -> Result<(), Error> {
self.custom_apis.insert(
Api::name(),
Arc::new(AnyWrapper::<Dispatcher, B, Api>(PhantomData)),
);
Ok(())
}
pub fn with_api<Dispatcher: Handler<Api, B> + 'static, Api: api::Api>(
mut self,
) -> Result<Self, Error> {
self.register_custom_api::<Dispatcher, Api>()?;
Ok(self)
}
}
impl<B> Default for ServerConfiguration<B>
where
B: Backend + Default,
{
fn default() -> Self {
Self::default_for(B::default())
}
}
#[cfg(feature = "acme")]
mod acme {
#[derive(Debug, Clone)]
pub struct AcmeConfiguration {
pub contact_email: Option<String>,
pub directory: String,
}
impl Default for AcmeConfiguration {
fn default() -> Self {
Self {
contact_email: None,
directory: LETS_ENCRYPT_PRODUCTION_DIRECTORY.to_string(),
}
}
}
pub use async_acme::acme::{LETS_ENCRYPT_PRODUCTION_DIRECTORY, LETS_ENCRYPT_STAGING_DIRECTORY};
}
#[cfg(feature = "acme")]
pub use acme::*;
#[derive(Debug, Clone)]
pub enum DefaultPermissions {
AllowAll,
Permissions(Permissions),
}
impl From<DefaultPermissions> for Permissions {
fn from(permissions: DefaultPermissions) -> Self {
match permissions {
DefaultPermissions::Permissions(permissions) => permissions,
DefaultPermissions::AllowAll => Self::allow_all(),
}
}
}
impl From<Permissions> for DefaultPermissions {
fn from(permissions: Permissions) -> Self {
Self::Permissions(permissions)
}
}
impl From<Vec<Statement>> for DefaultPermissions {
fn from(permissions: Vec<Statement>) -> Self {
Self::from(Permissions::from(permissions))
}
}
impl From<Statement> for DefaultPermissions {
fn from(permissions: Statement) -> Self {
Self::from(Permissions::from(permissions))
}
}
impl<B: Backend> Builder for ServerConfiguration<B> {
fn with_schema<S: Schema>(mut self) -> Result<Self, bonsaidb_local::Error> {
self.storage.register_schema::<S>()?;
Ok(self)
}
fn memory_only(mut self) -> Self {
self.storage.memory_only = true;
self
}
fn path<P: AsRef<Path>>(mut self, path: P) -> Self {
self.storage.path = Some(path.as_ref().to_owned());
self
}
fn unique_id(mut self, unique_id: u64) -> Self {
self.storage.unique_id = Some(unique_id);
self
}
#[cfg(feature = "encryption")]
fn vault_key_storage<VaultKeyStorage: AnyVaultKeyStorage>(
mut self,
key_storage: VaultKeyStorage,
) -> Self {
self.storage.vault_key_storage = Some(std::sync::Arc::new(key_storage));
self
}
#[cfg(feature = "encryption")]
fn default_encryption_key(mut self, key: KeyId) -> Self {
self.storage.default_encryption_key = Some(key);
self
}
fn tasks_worker_count(mut self, worker_count: usize) -> Self {
self.storage.workers.worker_count = worker_count;
self
}
fn tasks_parallelization(mut self, parallelization: usize) -> Self {
self.storage.workers.parallelization = parallelization;
self
}
fn check_view_integrity_on_open(mut self, check: bool) -> Self {
self.storage.views.check_integrity_on_open = check;
self
}
#[cfg(feature = "compression")]
fn default_compression(mut self, compression: Compression) -> Self {
self.storage.default_compression = Some(compression);
self
}
fn key_value_persistence(mut self, persistence: KeyValuePersistence) -> Self {
self.storage.key_value_persistence = persistence;
self
}
fn authenticated_permissions<P: Into<Permissions>>(
mut self,
authenticated_permissions: P,
) -> Self {
self.storage.authenticated_permissions = authenticated_permissions.into();
self
}
#[cfg(feature = "password-hashing")]
fn argon(mut self, argon: bonsaidb_local::config::ArgonConfiguration) -> Self {
self.storage.argon = argon;
self
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct BonsaiListenConfig {
pub address: SocketAddr,
pub reuse_address: bool,
}
impl Default for BonsaiListenConfig {
fn default() -> Self {
Self {
address: SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 5645, 0, 0)),
reuse_address: false,
}
}
}
impl BonsaiListenConfig {
#[must_use]
pub fn port(mut self, port: u16) -> Self {
self.address.set_port(port);
self
}
#[must_use]
pub const fn reuse_address(mut self, reuse_address: bool) -> Self {
self.reuse_address = reuse_address;
self
}
}
impl From<u16> for BonsaiListenConfig {
fn from(value: u16) -> Self {
Self::default().port(value)
}
}