sos_server_storage/
storage.rs

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
36/// Server storage backed by filesystem or database.
37pub enum ServerStorage {
38    /// Filesystem storage.
39    FileSystem(SyncImpl<ServerFileStorage>),
40    /// Database storage.
41    Database(SyncImpl<ServerDatabaseStorage>),
42}
43
44impl ServerStorage {
45    /// Create new server storage.
46    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    /// Create new file system storage.
71    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    /// Create an account in server storage.
95    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    /// Create a new file system account.
121    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    /// Create new database storage.
156    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    /// Create a new database account.
190    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    /*
288    async fn read_login_vault(&self) -> Result<Vault> {
289        match self {
290            ServerStorage::FileSystem(fs) => fs.read_login_vault().await,
291            ServerStorage::Database(db) => db.read_login_vault().await,
292        }
293    }
294    */
295
296    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}