bonsaidb_server/
config.rs

1use std::collections::HashMap;
2use std::marker::PhantomData;
3use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
4use std::path::Path;
5use std::sync::Arc;
6
7use bonsaidb_core::api;
8use bonsaidb_core::api::ApiName;
9#[cfg(feature = "encryption")]
10use bonsaidb_core::document::KeyId;
11use bonsaidb_core::permissions::{Permissions, Statement};
12use bonsaidb_core::schema::Schema;
13#[cfg(feature = "compression")]
14use bonsaidb_local::config::Compression;
15use bonsaidb_local::config::{Builder, KeyValuePersistence, StorageConfiguration};
16#[cfg(feature = "encryption")]
17use bonsaidb_local::vault::AnyVaultKeyStorage;
18
19use crate::api::{AnyHandler, AnyWrapper, Handler};
20use crate::{Backend, Error, NoBackend};
21
22/// Configuration options for [`Server`](crate::Server)
23#[derive(Debug, Clone)]
24#[must_use]
25#[non_exhaustive]
26pub struct ServerConfiguration<B: Backend = NoBackend> {
27    /// The [`Backend`] for the server.
28    pub backend: B,
29    /// The DNS name of the server.
30    pub server_name: String,
31    /// Number of sumultaneous requests a single client can have in flight at a
32    /// time. Default value is 16. It is important to have this number be tuned
33    /// relative to `request_workers` such that one client cannot overwhelm the
34    /// entire queue.
35    pub client_simultaneous_request_limit: usize,
36    /// Number of simultaneous requests to be processed. Default value is 16.
37    pub request_workers: usize,
38    /// Configuration options for individual databases.
39    pub storage: StorageConfiguration,
40    /// The permissions granted to all connections to this server.
41    pub default_permissions: DefaultPermissions,
42    /// The ACME settings for automatic TLS certificate management.
43    #[cfg(feature = "acme")]
44    pub acme: AcmeConfiguration,
45
46    pub(crate) custom_apis: HashMap<ApiName, Arc<dyn AnyHandler<B>>>,
47}
48
49impl<B: Backend> ServerConfiguration<B> {
50    /// Returns a default configuration for the given backend.
51    pub fn default_for(backend: B) -> Self {
52        Self {
53            backend,
54            server_name: String::from("bonsaidb"),
55            client_simultaneous_request_limit: 16,
56            // TODO this was arbitrarily picked, it probably should be higher,
57            // but it also should probably be based on the cpu's capabilities
58            request_workers: 16,
59            storage: bonsaidb_local::config::StorageConfiguration::default(),
60            default_permissions: DefaultPermissions::Permissions(Permissions::default()),
61            custom_apis: HashMap::default(),
62            #[cfg(feature = "acme")]
63            acme: AcmeConfiguration::default(),
64        }
65    }
66
67    /// Returns a default configuration for the given backend and path.
68    pub fn new_with_backend<P: AsRef<Path>>(path: P, backend: B) -> Self {
69        Self::default_for(backend).path(path)
70    }
71
72    /// Sets [`Self::server_name`](Self#structfield.server_name) to `server_name` and returns self.
73    pub fn server_name(mut self, server_name: impl Into<String>) -> Self {
74        self.server_name = server_name.into();
75        self
76    }
77
78    /// Sets [`Self::client_simultaneous_request_limit`](Self#structfield.client_simultaneous_request_limit) to `request_limit` and returns self.
79    pub const fn client_simultaneous_request_limit(mut self, request_limit: usize) -> Self {
80        self.client_simultaneous_request_limit = request_limit;
81        self
82    }
83
84    /// Sets [`Self::request_workers`](Self#structfield.request_workers) to `workers` and returns self.
85    pub const fn request_workers(mut self, workers: usize) -> Self {
86        self.request_workers = workers;
87        self
88    }
89
90    /// Sets [`Self::default_permissions`](Self#structfield.default_permissions) to `default_permissions` and returns self.
91    pub fn default_permissions<P: Into<DefaultPermissions>>(
92        mut self,
93        default_permissions: P,
94    ) -> Self {
95        self.default_permissions = default_permissions.into();
96        self
97    }
98
99    /// Sets [`AcmeConfiguration::contact_email`] to `contact_email` and returns self.
100    #[cfg(feature = "acme")]
101    pub fn acme_contact_email(mut self, contact_email: impl Into<String>) -> Self {
102        self.acme.contact_email = Some(contact_email.into());
103        self
104    }
105
106    /// Sets [`AcmeConfiguration::directory`] to `directory` and returns self.
107    #[cfg(feature = "acme")]
108    pub fn acme_directory(mut self, directory: impl Into<String>) -> Self {
109        self.acme.directory = directory.into();
110        self
111    }
112
113    /// Registers a `handler` for a [`Api`][api::Api]. When an [`Api`][api::Api] is
114    /// received by the server, the handler will be invoked
115    pub fn register_custom_api<Dispatcher: Handler<Api, B> + 'static, Api: api::Api>(
116        &mut self,
117    ) -> Result<(), Error> {
118        // TODO this should error on duplicate registration.
119        self.custom_apis.insert(
120            Api::name(),
121            Arc::new(AnyWrapper::<Dispatcher, B, Api>(PhantomData)),
122        );
123        Ok(())
124    }
125
126    /// Registers the custom api dispatcher and returns self.
127    pub fn with_api<Dispatcher: Handler<Api, B> + 'static, Api: api::Api>(
128        mut self,
129    ) -> Result<Self, Error> {
130        self.register_custom_api::<Dispatcher, Api>()?;
131        Ok(self)
132    }
133}
134
135impl<B> Default for ServerConfiguration<B>
136where
137    B: Backend + Default,
138{
139    fn default() -> Self {
140        Self::default_for(B::default())
141    }
142}
143
144#[cfg(feature = "acme")]
145mod acme {
146    /// The Automated Certificate Management Environment (ACME) configuration.
147    #[derive(Debug, Clone)]
148    pub struct AcmeConfiguration {
149        /// The contact email to register with the ACME directory for the account.
150        pub contact_email: Option<String>,
151        /// The ACME directory to use for registration. The default is
152        /// [`LETS_ENCRYPT_PRODUCTION_DIRECTORY`].
153        pub directory: String,
154    }
155
156    impl Default for AcmeConfiguration {
157        fn default() -> Self {
158            Self {
159                contact_email: None,
160                directory: LETS_ENCRYPT_PRODUCTION_DIRECTORY.to_string(),
161            }
162        }
163    }
164
165    pub use async_acme::acme::{LETS_ENCRYPT_PRODUCTION_DIRECTORY, LETS_ENCRYPT_STAGING_DIRECTORY};
166}
167
168#[cfg(feature = "acme")]
169pub use acme::*;
170
171/// The default permissions to use for all connections to the server.
172#[derive(Debug, Clone)]
173pub enum DefaultPermissions {
174    /// Allow all permissions. Do not use outside of completely trusted environments.
175    AllowAll,
176    /// A defined set of permissions.
177    Permissions(Permissions),
178}
179
180impl From<DefaultPermissions> for Permissions {
181    fn from(permissions: DefaultPermissions) -> Self {
182        match permissions {
183            DefaultPermissions::Permissions(permissions) => permissions,
184            DefaultPermissions::AllowAll => Self::allow_all(),
185        }
186    }
187}
188
189impl From<Permissions> for DefaultPermissions {
190    fn from(permissions: Permissions) -> Self {
191        Self::Permissions(permissions)
192    }
193}
194
195impl From<Vec<Statement>> for DefaultPermissions {
196    fn from(permissions: Vec<Statement>) -> Self {
197        Self::from(Permissions::from(permissions))
198    }
199}
200
201impl From<Statement> for DefaultPermissions {
202    fn from(permissions: Statement) -> Self {
203        Self::from(Permissions::from(permissions))
204    }
205}
206
207impl<B: Backend> Builder for ServerConfiguration<B> {
208    fn with_schema<S: Schema>(mut self) -> Result<Self, bonsaidb_local::Error> {
209        self.storage.register_schema::<S>()?;
210        Ok(self)
211    }
212
213    fn memory_only(mut self) -> Self {
214        self.storage.memory_only = true;
215        self
216    }
217
218    fn path<P: AsRef<Path>>(mut self, path: P) -> Self {
219        self.storage.path = Some(path.as_ref().to_owned());
220        self
221    }
222
223    fn unique_id(mut self, unique_id: u64) -> Self {
224        self.storage.unique_id = Some(unique_id);
225        self
226    }
227
228    #[cfg(feature = "encryption")]
229    fn vault_key_storage<VaultKeyStorage: AnyVaultKeyStorage>(
230        mut self,
231        key_storage: VaultKeyStorage,
232    ) -> Self {
233        self.storage.vault_key_storage = Some(std::sync::Arc::new(key_storage));
234        self
235    }
236
237    #[cfg(feature = "encryption")]
238    fn default_encryption_key(mut self, key: KeyId) -> Self {
239        self.storage.default_encryption_key = Some(key);
240        self
241    }
242
243    fn tasks_worker_count(mut self, worker_count: usize) -> Self {
244        self.storage.workers.worker_count = worker_count;
245        self
246    }
247
248    fn tasks_parallelization(mut self, parallelization: usize) -> Self {
249        self.storage.workers.parallelization = parallelization;
250        self
251    }
252
253    fn check_view_integrity_on_open(mut self, check: bool) -> Self {
254        self.storage.views.check_integrity_on_open = check;
255        self
256    }
257
258    #[cfg(feature = "compression")]
259    fn default_compression(mut self, compression: Compression) -> Self {
260        self.storage.default_compression = Some(compression);
261        self
262    }
263
264    fn key_value_persistence(mut self, persistence: KeyValuePersistence) -> Self {
265        self.storage.key_value_persistence = persistence;
266        self
267    }
268
269    fn authenticated_permissions<P: Into<Permissions>>(
270        mut self,
271        authenticated_permissions: P,
272    ) -> Self {
273        self.storage.authenticated_permissions = authenticated_permissions.into();
274        self
275    }
276
277    #[cfg(feature = "password-hashing")]
278    fn argon(mut self, argon: bonsaidb_local::config::ArgonConfiguration) -> Self {
279        self.storage.argon = argon;
280        self
281    }
282}
283
284/// Configuration for the BonsaiDb network protocol.
285///
286/// The BonsaiDb network protocol is built using QUIC, which uses UDP instead of
287/// TCP.
288#[derive(Clone, Copy, Debug)]
289#[non_exhaustive]
290pub struct BonsaiListenConfig {
291    /// The socket port to listen for connections on.
292    ///
293    /// By default, this is `[::]:5645`.
294    pub address: SocketAddr,
295
296    /// If this is set to true, the `SO_REUSEADDR` flag will be set on the
297    /// listening socket.
298    ///
299    /// This informs the operating system that it should allow reusing the exact
300    /// same address/port combination in the future, which enables restarting a
301    /// BonsaiDb network protocol listener without restarting the process
302    /// itself. In general, this is not needed for users in regular deployments,
303    /// and is more useful for specific kinds of testing.
304    pub reuse_address: bool,
305}
306
307impl Default for BonsaiListenConfig {
308    fn default() -> Self {
309        Self {
310            address: SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 5645, 0, 0)),
311            reuse_address: false,
312        }
313    }
314}
315
316impl BonsaiListenConfig {
317    /// Sets the port for the socket address, and returns the updated config.
318    #[must_use]
319    pub fn port(mut self, port: u16) -> Self {
320        self.address.set_port(port);
321        self
322    }
323
324    /// Sets the [`reuse_address`](Self::reuse_address) flag.
325    #[must_use]
326    pub const fn reuse_address(mut self, reuse_address: bool) -> Self {
327        self.reuse_address = reuse_address;
328        self
329    }
330}
331
332impl From<u16> for BonsaiListenConfig {
333    fn from(value: u16) -> Self {
334        Self::default().port(value)
335    }
336}