1use crate::{
2 database::ServerDatabaseStorage, filesystem::ServerFileStorage, Error,
3 Result, ServerAccountStorage,
4};
5use async_trait::async_trait;
6use indexmap::IndexSet;
7use sos_backend::{
8 AccountEventLog, BackendTarget, DeviceEventLog, FolderEventLog,
9};
10use sos_core::{
11 commit::{CommitState, Comparison},
12 device::{DevicePublicKey, TrustedDevice},
13 events::{
14 patch::{AccountDiff, CheckedPatch, DeviceDiff, FolderDiff},
15 EventLog, WriteEvent,
16 },
17 AccountId, Paths, VaultFlags, VaultId,
18};
19use sos_database::entity::AccountEntity;
20use sos_sync::{
21 CreateSet, ForceMerge, Merge, MergeOutcome, StorageEventLogs, SyncStatus,
22 SyncStorage,
23};
24use sos_vault::{Summary, Vault};
25use std::{
26 collections::{HashMap, HashSet},
27 sync::Arc,
28};
29use tokio::sync::RwLock;
30
31#[cfg(feature = "files")]
32use {sos_backend::FileEventLog, sos_core::events::patch::FileDiff};
33
34use crate::sync::SyncImpl;
35
36pub enum ServerStorage {
38 FileSystem(SyncImpl<ServerFileStorage>),
40 Database(SyncImpl<ServerDatabaseStorage>),
42}
43
44impl ServerStorage {
45 pub async fn new(
47 target: BackendTarget,
48 account_id: &AccountId,
49 ) -> Result<Self> {
50 match target {
51 BackendTarget::FileSystem(paths) => {
52 Self::new_fs(
53 BackendTarget::FileSystem(
54 paths.with_account_id(account_id),
55 ),
56 account_id,
57 )
58 .await
59 }
60 BackendTarget::Database(paths, client) => {
61 Self::new_db(
62 BackendTarget::Database(paths, client),
63 account_id,
64 )
65 .await
66 }
67 }
68 }
69
70 async fn new_fs(
72 target: BackendTarget,
73 account_id: &AccountId,
74 ) -> Result<Self> {
75 debug_assert!(matches!(target, BackendTarget::FileSystem(_)));
76 debug_assert!(target.paths().is_server());
77
78 let target = target.with_account_id(account_id);
79 let mut event_log =
80 FolderEventLog::new_login_folder(target.clone(), account_id)
81 .await?;
82 event_log.load_tree().await?;
83
84 Ok(Self::FileSystem(SyncImpl::new(
85 ServerFileStorage::new(
86 target,
87 account_id,
88 Arc::new(RwLock::new(event_log)),
89 )
90 .await?,
91 )))
92 }
93
94 pub async fn create_account(
96 target: BackendTarget,
97 account_id: &AccountId,
98 account_data: &CreateSet,
99 ) -> Result<Self> {
100 match target {
101 BackendTarget::FileSystem(paths) => {
102 Self::create_fs_account(
103 BackendTarget::FileSystem(paths),
104 account_id,
105 account_data,
106 )
107 .await
108 }
109 BackendTarget::Database(paths, client) => {
110 Self::create_db_account(
111 BackendTarget::Database(paths, client),
112 account_id,
113 account_data,
114 )
115 .await
116 }
117 }
118 }
119
120 async fn create_fs_account(
122 target: BackendTarget,
123 account_id: &AccountId,
124 account_data: &CreateSet,
125 ) -> Result<Self> {
126 debug_assert!(matches!(target, BackendTarget::FileSystem(_)));
127 let BackendTarget::FileSystem(paths) = &target else {
128 panic!("filesystem backend expected");
129 };
130 debug_assert!(paths.is_server());
131
132 let paths = paths.with_account_id(account_id);
133 paths.ensure().await?;
134
135 let identity_log = ServerFileStorage::initialize_account(
136 &target,
137 account_id,
138 &paths,
139 &account_data.identity,
140 )
141 .await?;
142
143 let target = target.with_account_id(account_id);
144 let mut storage = ServerFileStorage::new(
145 target,
146 account_id,
147 Arc::new(RwLock::new(identity_log)),
148 )
149 .await?;
150 storage.import_account(&account_data).await?;
151
152 Ok(Self::FileSystem(SyncImpl::new(storage)))
153 }
154
155 async fn new_db(
157 target: BackendTarget,
158 account_id: &AccountId,
159 ) -> Result<Self> {
160 debug_assert!(matches!(target, BackendTarget::Database(_, _)));
161 let BackendTarget::Database(paths, client) = &target else {
162 panic!("database backend expected");
163 };
164 debug_assert!(paths.is_server());
165
166 let (_, login_folder) =
167 AccountEntity::find_account_with_login(&client, account_id)
168 .await?;
169
170 let mut event_log = FolderEventLog::new_folder(
171 target.clone(),
172 account_id,
173 login_folder.summary.id(),
174 )
175 .await?;
176 event_log.load_tree().await?;
177
178 let target = target.with_account_id(account_id);
179 Ok(Self::Database(SyncImpl::new(
180 ServerDatabaseStorage::new(
181 target,
182 account_id,
183 Arc::new(RwLock::new(event_log)),
184 )
185 .await?,
186 )))
187 }
188
189 async fn create_db_account(
191 target: BackendTarget,
192 account_id: &AccountId,
193 account_data: &CreateSet,
194 ) -> Result<Self> {
195 let BackendTarget::Database(paths, _) = &target else {
196 panic!("database backend expected");
197 };
198 debug_assert!(paths.is_server());
199
200 let identity_log = ServerDatabaseStorage::initialize_account(
201 &target,
202 account_id,
203 &account_data.identity,
204 )
205 .await?;
206
207 let target = target.with_account_id(account_id);
208 let mut storage = ServerDatabaseStorage::new(
209 target,
210 account_id,
211 Arc::new(RwLock::new(identity_log)),
212 )
213 .await?;
214 storage.import_account(&account_data).await?;
215
216 Ok(Self::Database(SyncImpl::new(storage)))
217 }
218}
219
220#[async_trait]
221impl ServerAccountStorage for ServerStorage {
222 fn account_id(&self) -> &AccountId {
223 match self {
224 ServerStorage::FileSystem(fs) => fs.account_id(),
225 ServerStorage::Database(db) => db.account_id(),
226 }
227 }
228
229 fn list_device_keys(&self) -> HashSet<&DevicePublicKey> {
230 match self {
231 ServerStorage::FileSystem(fs) => fs.list_device_keys(),
232 ServerStorage::Database(db) => db.list_device_keys(),
233 }
234 }
235
236 fn paths(&self) -> Arc<Paths> {
237 match self {
238 ServerStorage::FileSystem(fs) => fs.paths(),
239 ServerStorage::Database(db) => db.paths(),
240 }
241 }
242
243 fn folders(&self) -> &HashMap<VaultId, Arc<RwLock<FolderEventLog>>> {
244 match self {
245 ServerStorage::FileSystem(fs) => fs.folders(),
246 ServerStorage::Database(db) => db.folders(),
247 }
248 }
249
250 fn folders_mut(
251 &mut self,
252 ) -> &mut HashMap<VaultId, Arc<RwLock<FolderEventLog>>> {
253 match self {
254 ServerStorage::FileSystem(fs) => fs.folders_mut(),
255 ServerStorage::Database(db) => db.folders_mut(),
256 }
257 }
258
259 fn set_devices(&mut self, devices: IndexSet<TrustedDevice>) {
260 match self {
261 ServerStorage::FileSystem(fs) => fs.set_devices(devices),
262 ServerStorage::Database(db) => db.set_devices(devices),
263 }
264 }
265
266 async fn rename_account(&self, name: &str) -> Result<()> {
267 match self {
268 ServerStorage::FileSystem(fs) => fs.rename_account(name).await,
269 ServerStorage::Database(db) => db.rename_account(name).await,
270 }
271 }
272
273 async fn read_vault(&self, folder_id: &VaultId) -> Result<Vault> {
274 match self {
275 ServerStorage::FileSystem(fs) => fs.read_vault(folder_id).await,
276 ServerStorage::Database(db) => db.read_vault(folder_id).await,
277 }
278 }
279
280 async fn write_vault(&self, vault: &Vault) -> Result<()> {
281 match self {
282 ServerStorage::FileSystem(fs) => fs.write_vault(vault).await,
283 ServerStorage::Database(db) => db.write_vault(vault).await,
284 }
285 }
286
287 async fn write_login_vault(&self, vault: &Vault) -> Result<()> {
297 match self {
298 ServerStorage::FileSystem(fs) => {
299 fs.write_login_vault(vault).await
300 }
301 ServerStorage::Database(db) => db.write_login_vault(vault).await,
302 }
303 }
304
305 async fn replace_folder(
306 &self,
307 folder_id: &VaultId,
308 diff: &FolderDiff,
309 ) -> Result<(FolderEventLog, Vault)> {
310 match self {
311 ServerStorage::FileSystem(fs) => {
312 fs.replace_folder(folder_id, diff).await
313 }
314 ServerStorage::Database(db) => {
315 db.replace_folder(folder_id, diff).await
316 }
317 }
318 }
319
320 async fn set_folder_flags(
321 &self,
322 folder_id: &VaultId,
323 flags: VaultFlags,
324 ) -> Result<()> {
325 match self {
326 ServerStorage::FileSystem(fs) => {
327 fs.set_folder_flags(folder_id, flags).await
328 }
329 ServerStorage::Database(db) => {
330 db.set_folder_flags(folder_id, flags).await
331 }
332 }
333 }
334
335 async fn import_account(
336 &mut self,
337 account_data: &CreateSet,
338 ) -> Result<()> {
339 match self {
340 ServerStorage::FileSystem(fs) => {
341 fs.import_account(account_data).await
342 }
343 ServerStorage::Database(db) => {
344 db.import_account(account_data).await
345 }
346 }
347 }
348
349 async fn load_folders(&mut self) -> Result<Vec<Summary>> {
350 match self {
351 ServerStorage::FileSystem(fs) => fs.load_folders().await,
352 ServerStorage::Database(db) => db.load_folders().await,
353 }
354 }
355
356 async fn import_folder(
357 &mut self,
358 id: &VaultId,
359 buffer: &[u8],
360 ) -> Result<()> {
361 match self {
362 ServerStorage::FileSystem(fs) => {
363 fs.import_folder(id, buffer).await
364 }
365 ServerStorage::Database(db) => db.import_folder(id, buffer).await,
366 }
367 }
368
369 async fn rename_folder(
370 &mut self,
371 id: &VaultId,
372 name: &str,
373 ) -> Result<()> {
374 match self {
375 ServerStorage::FileSystem(fs) => fs.rename_folder(id, name).await,
376 ServerStorage::Database(db) => db.rename_folder(id, name).await,
377 }
378 }
379
380 async fn delete_folder(&mut self, id: &VaultId) -> Result<()> {
381 match self {
382 ServerStorage::FileSystem(fs) => fs.delete_folder(id).await,
383 ServerStorage::Database(db) => db.delete_folder(id).await,
384 }
385 }
386
387 async fn delete_account(&mut self) -> Result<()> {
388 match self {
389 ServerStorage::FileSystem(fs) => fs.delete_account().await,
390 ServerStorage::Database(db) => db.delete_account().await,
391 }
392 }
393}
394
395#[async_trait]
396impl Merge for ServerStorage {
397 async fn merge_identity(
398 &mut self,
399 diff: FolderDiff,
400 outcome: &mut MergeOutcome,
401 ) -> Result<CheckedPatch> {
402 match self {
403 ServerStorage::FileSystem(fs) => {
404 fs.merge_identity(diff, outcome).await
405 }
406 ServerStorage::Database(db) => {
407 db.merge_identity(diff, outcome).await
408 }
409 }
410 }
411
412 async fn compare_identity(
413 &self,
414 state: &CommitState,
415 ) -> Result<Comparison> {
416 match self {
417 ServerStorage::FileSystem(fs) => fs.compare_identity(state).await,
418 ServerStorage::Database(db) => db.compare_identity(state).await,
419 }
420 }
421
422 async fn merge_account(
423 &mut self,
424 diff: AccountDiff,
425 outcome: &mut MergeOutcome,
426 ) -> Result<(CheckedPatch, HashSet<VaultId>)> {
427 match self {
428 ServerStorage::FileSystem(fs) => {
429 fs.merge_account(diff, outcome).await
430 }
431 ServerStorage::Database(db) => {
432 db.merge_account(diff, outcome).await
433 }
434 }
435 }
436
437 async fn compare_account(
438 &self,
439 state: &CommitState,
440 ) -> Result<Comparison> {
441 match self {
442 ServerStorage::FileSystem(fs) => fs.compare_account(state).await,
443 ServerStorage::Database(db) => db.compare_account(state).await,
444 }
445 }
446
447 async fn merge_device(
448 &mut self,
449 diff: DeviceDiff,
450 outcome: &mut MergeOutcome,
451 ) -> Result<CheckedPatch> {
452 match self {
453 ServerStorage::FileSystem(fs) => {
454 fs.merge_device(diff, outcome).await
455 }
456 ServerStorage::Database(db) => {
457 db.merge_device(diff, outcome).await
458 }
459 }
460 }
461
462 async fn compare_device(
463 &self,
464 state: &CommitState,
465 ) -> Result<Comparison> {
466 match self {
467 ServerStorage::FileSystem(fs) => fs.compare_device(state).await,
468 ServerStorage::Database(db) => db.compare_device(state).await,
469 }
470 }
471
472 #[cfg(feature = "files")]
473 async fn merge_files(
474 &mut self,
475 diff: FileDiff,
476 outcome: &mut MergeOutcome,
477 ) -> Result<CheckedPatch> {
478 match self {
479 ServerStorage::FileSystem(fs) => {
480 fs.merge_files(diff, outcome).await
481 }
482 ServerStorage::Database(db) => {
483 db.merge_files(diff, outcome).await
484 }
485 }
486 }
487
488 #[cfg(feature = "files")]
489 async fn compare_files(&self, state: &CommitState) -> Result<Comparison> {
490 match self {
491 ServerStorage::FileSystem(fs) => fs.compare_files(state).await,
492 ServerStorage::Database(db) => db.compare_files(state).await,
493 }
494 }
495
496 async fn merge_folder(
497 &mut self,
498 folder_id: &VaultId,
499 diff: FolderDiff,
500 outcome: &mut MergeOutcome,
501 ) -> Result<(CheckedPatch, Vec<WriteEvent>)> {
502 match self {
503 ServerStorage::FileSystem(fs) => {
504 fs.merge_folder(folder_id, diff, outcome).await
505 }
506 ServerStorage::Database(db) => {
507 db.merge_folder(folder_id, diff, outcome).await
508 }
509 }
510 }
511
512 async fn compare_folder(
513 &self,
514 folder_id: &VaultId,
515 state: &CommitState,
516 ) -> Result<Comparison> {
517 match self {
518 ServerStorage::FileSystem(fs) => {
519 fs.compare_folder(folder_id, state).await
520 }
521 ServerStorage::Database(db) => {
522 db.compare_folder(folder_id, state).await
523 }
524 }
525 }
526}
527
528#[async_trait]
529impl ForceMerge for ServerStorage {
530 async fn force_merge_identity(
531 &mut self,
532 diff: FolderDiff,
533 outcome: &mut MergeOutcome,
534 ) -> Result<()> {
535 match self {
536 ServerStorage::FileSystem(fs) => {
537 fs.force_merge_identity(diff, outcome).await
538 }
539 ServerStorage::Database(db) => {
540 db.force_merge_identity(diff, outcome).await
541 }
542 }
543 }
544
545 async fn force_merge_account(
546 &mut self,
547 diff: AccountDiff,
548 outcome: &mut MergeOutcome,
549 ) -> Result<()> {
550 match self {
551 ServerStorage::FileSystem(fs) => {
552 fs.force_merge_account(diff, outcome).await
553 }
554 ServerStorage::Database(db) => {
555 db.force_merge_account(diff, outcome).await
556 }
557 }
558 }
559
560 async fn force_merge_device(
561 &mut self,
562 diff: DeviceDiff,
563 outcome: &mut MergeOutcome,
564 ) -> Result<()> {
565 match self {
566 ServerStorage::FileSystem(fs) => {
567 fs.force_merge_device(diff, outcome).await
568 }
569 ServerStorage::Database(db) => {
570 db.force_merge_device(diff, outcome).await
571 }
572 }
573 }
574
575 #[cfg(feature = "files")]
576 async fn force_merge_files(
577 &mut self,
578 diff: FileDiff,
579 outcome: &mut MergeOutcome,
580 ) -> Result<()> {
581 match self {
582 ServerStorage::FileSystem(fs) => {
583 fs.force_merge_files(diff, outcome).await
584 }
585 ServerStorage::Database(db) => {
586 db.force_merge_files(diff, outcome).await
587 }
588 }
589 }
590
591 async fn force_merge_folder(
592 &mut self,
593 folder_id: &VaultId,
594 diff: FolderDiff,
595 outcome: &mut MergeOutcome,
596 ) -> Result<()> {
597 match self {
598 ServerStorage::FileSystem(fs) => {
599 fs.force_merge_folder(folder_id, diff, outcome).await
600 }
601 ServerStorage::Database(db) => {
602 db.force_merge_folder(folder_id, diff, outcome).await
603 }
604 }
605 }
606}
607
608#[async_trait]
609impl StorageEventLogs for ServerStorage {
610 type Error = Error;
611
612 async fn identity_log(&self) -> Result<Arc<RwLock<FolderEventLog>>> {
613 match self {
614 ServerStorage::FileSystem(fs) => fs.identity_log().await,
615 ServerStorage::Database(db) => db.identity_log().await,
616 }
617 }
618
619 async fn account_log(&self) -> Result<Arc<RwLock<AccountEventLog>>> {
620 match self {
621 ServerStorage::FileSystem(fs) => fs.account_log().await,
622 ServerStorage::Database(db) => db.account_log().await,
623 }
624 }
625
626 async fn device_log(&self) -> Result<Arc<RwLock<DeviceEventLog>>> {
627 match self {
628 ServerStorage::FileSystem(fs) => fs.device_log().await,
629 ServerStorage::Database(db) => db.device_log().await,
630 }
631 }
632
633 #[cfg(feature = "files")]
634 async fn file_log(&self) -> Result<Arc<RwLock<FileEventLog>>> {
635 match self {
636 ServerStorage::FileSystem(fs) => fs.file_log().await,
637 ServerStorage::Database(db) => db.file_log().await,
638 }
639 }
640
641 async fn folder_details(&self) -> Result<IndexSet<Summary>> {
642 match self {
643 ServerStorage::FileSystem(fs) => fs.folder_details().await,
644 ServerStorage::Database(db) => db.folder_details().await,
645 }
646 }
647
648 async fn folder_log(
649 &self,
650 id: &VaultId,
651 ) -> Result<Arc<RwLock<FolderEventLog>>> {
652 match self {
653 ServerStorage::FileSystem(fs) => fs.folder_log(id).await,
654 ServerStorage::Database(db) => db.folder_log(id).await,
655 }
656 }
657}
658
659#[async_trait]
660impl SyncStorage for ServerStorage {
661 fn is_client_storage(&self) -> bool {
662 false
663 }
664
665 async fn sync_status(&self) -> Result<SyncStatus> {
666 match self {
667 ServerStorage::FileSystem(fs) => fs.sync_status().await,
668 ServerStorage::Database(db) => db.sync_status().await,
669 }
670 }
671}