bonsaidb_server/
config.rs1use 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#[derive(Debug, Clone)]
24#[must_use]
25#[non_exhaustive]
26pub struct ServerConfiguration<B: Backend = NoBackend> {
27 pub backend: B,
29 pub server_name: String,
31 pub client_simultaneous_request_limit: usize,
36 pub request_workers: usize,
38 pub storage: StorageConfiguration,
40 pub default_permissions: DefaultPermissions,
42 #[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 pub fn default_for(backend: B) -> Self {
52 Self {
53 backend,
54 server_name: String::from("bonsaidb"),
55 client_simultaneous_request_limit: 16,
56 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 pub fn new_with_backend<P: AsRef<Path>>(path: P, backend: B) -> Self {
69 Self::default_for(backend).path(path)
70 }
71
72 pub fn server_name(mut self, server_name: impl Into<String>) -> Self {
74 self.server_name = server_name.into();
75 self
76 }
77
78 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 pub const fn request_workers(mut self, workers: usize) -> Self {
86 self.request_workers = workers;
87 self
88 }
89
90 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 #[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 #[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 pub fn register_custom_api<Dispatcher: Handler<Api, B> + 'static, Api: api::Api>(
116 &mut self,
117 ) -> Result<(), Error> {
118 self.custom_apis.insert(
120 Api::name(),
121 Arc::new(AnyWrapper::<Dispatcher, B, Api>(PhantomData)),
122 );
123 Ok(())
124 }
125
126 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 #[derive(Debug, Clone)]
148 pub struct AcmeConfiguration {
149 pub contact_email: Option<String>,
151 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#[derive(Debug, Clone)]
173pub enum DefaultPermissions {
174 AllowAll,
176 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#[derive(Clone, Copy, Debug)]
289#[non_exhaustive]
290pub struct BonsaiListenConfig {
291 pub address: SocketAddr,
295
296 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 #[must_use]
319 pub fn port(mut self, port: u16) -> Self {
320 self.address.set_port(port);
321 self
322 }
323
324 #[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}