sos_protocol/
traits.rs

1use crate::{
2    DiffRequest, DiffResponse, PatchRequest, PatchResponse, ScanRequest,
3    ScanResponse, SyncOptions,
4};
5use async_trait::async_trait;
6use sos_core::Origin;
7use sos_sync::{CreateSet, MergeOutcome, SyncPacket, SyncStatus, UpdateSet};
8
9/// Result of a sync operation with a single remote.
10#[derive(Debug)]
11pub struct RemoteResult<E> {
12    /// Origin of the remote.
13    pub origin: Origin,
14    /// Result of the sync operation.
15    pub result: Result<Option<MergeOutcome>, E>,
16}
17
18/// Result of a sync operation.
19#[derive(Debug)]
20pub struct SyncResult<E> {
21    /// Result of syncing with remote data sources.
22    pub remotes: Vec<RemoteResult<E>>,
23}
24
25impl<E> Default for SyncResult<E> {
26    fn default() -> Self {
27        Self {
28            remotes: Vec::new(),
29        }
30    }
31}
32
33impl<E> SyncResult<E> {
34    /// Find the first sync error.
35    pub fn first_error(self) -> Option<E> {
36        self.remotes.into_iter().find_map(|res| {
37            if res.result.is_err() {
38                res.result.err()
39            } else {
40                None
41            }
42        })
43    }
44
45    /// Find the first sync error by reference.
46    pub fn first_error_ref(&self) -> Option<&E> {
47        self.remotes.iter().find_map(|res| {
48            if let Err(e) = &res.result {
49                Some(e)
50            } else {
51                None
52            }
53        })
54    }
55
56    /// Determine if the sync has one or more errors.
57    pub fn has_error(&self) -> bool {
58        self.remotes.iter().any(|r| r.result.is_err())
59    }
60}
61
62/// Trait for types that can sync with a single remote.
63#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
64#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
65pub trait RemoteSync {
66    /// Error type for remote sync.
67    type Error: std::error::Error + std::fmt::Debug;
68
69    /// Perform a full sync of the account using
70    /// the default options.
71    ///
72    /// If the account does not exist on the remote
73    /// server the account will be created and
74    /// [RemoteSync::sync_file_transfers] will be called
75    /// to ensure the transfers queue is synced.
76    async fn sync(&self) -> RemoteResult<Self::Error>;
77
78    /// Perform a full sync of the account
79    /// using the given options.
80    ///
81    /// See the documentation for [RemoteSync::sync] for more details.
82    async fn sync_with_options(
83        &self,
84        options: &SyncOptions,
85    ) -> RemoteResult<Self::Error>;
86
87    /// Force update an account on remote servers.
88    ///
89    /// Should be called after making destructive
90    /// changes to an account's folders. For example, if
91    /// the encryption cipher has been changed, a folder
92    /// password was changed or folder(s) were compacted.
93    async fn force_update(
94        &self,
95        account_data: UpdateSet,
96    ) -> RemoteResult<Self::Error>;
97
98    /// Sync file transfers.
99    ///
100    /// Updates the file transfers queue with any pending
101    /// uploads or downloads by comparing the local file
102    /// state with the file state on remote server(s).
103    #[cfg(feature = "files")]
104    async fn sync_file_transfers(&self) -> RemoteResult<Self::Error>;
105}
106
107/// Trait for types that can sync with multiple remotes.
108#[async_trait]
109pub trait AccountSync {
110    /// Error type for account sync.
111    type Error: std::error::Error + std::fmt::Debug;
112
113    /// Perform a full sync of the account using
114    /// the default options.
115    ///
116    /// If the account does not exist on the remote
117    /// server the account will be created and
118    /// [RemoteSync::sync_file_transfers] will be called
119    /// to ensure the transfers queue is synced.
120    async fn sync(&self) -> SyncResult<Self::Error>;
121
122    /// Perform a full sync of the account
123    /// using the given options.
124    ///
125    /// See the documentation for [RemoteSync::sync] for more details.
126    async fn sync_with_options(
127        &self,
128        options: &SyncOptions,
129    ) -> SyncResult<Self::Error>;
130
131    /// Sync file transfers.
132    ///
133    /// Updates the file transfers queue with any pending
134    /// uploads or downloads by comparing the local file
135    /// state with the file state on remote server(s).
136    #[cfg(feature = "files")]
137    async fn sync_file_transfers(
138        &self,
139        options: &SyncOptions,
140    ) -> SyncResult<Self::Error>;
141
142    /// Force update an account on remote servers.
143    ///
144    /// Should be called after making destructive
145    /// changes to an account's folders. For example, if
146    /// the encryption cipher has been changed, a folder
147    /// password was changed or folder(s) were compacted.
148    async fn force_update(
149        &self,
150        account_data: UpdateSet,
151        options: &SyncOptions,
152    ) -> SyncResult<Self::Error>;
153}
154
155/// Client that can communicate with a remote data source.
156#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
157#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
158pub trait SyncClient {
159    /// Error type for sync client.
160    type Error: std::error::Error + std::fmt::Debug;
161
162    /// Origin of the remote server.
163    fn origin(&self) -> &Origin;
164
165    /// Check if an account already exists.
166    async fn account_exists(&self) -> Result<bool, Self::Error>;
167
168    /// Create a new account.
169    async fn create_account(
170        &self,
171        account: CreateSet,
172    ) -> Result<(), Self::Error>;
173
174    /// Update an account.
175    async fn update_account(
176        &self,
177        account: UpdateSet,
178    ) -> Result<(), Self::Error>;
179
180    /// Fetch an account from a remote server.
181    async fn fetch_account(&self) -> Result<CreateSet, Self::Error>;
182
183    /// Delete the account on the server.
184    async fn delete_account(&self) -> Result<(), Self::Error>;
185
186    /// Sync status on the server.
187    async fn sync_status(&self) -> Result<SyncStatus, Self::Error>;
188
189    /// Sync with a remote.
190    async fn sync(
191        &self,
192        packet: SyncPacket,
193    ) -> Result<SyncPacket, Self::Error>;
194
195    /// Scan commits in an event log.
196    async fn scan(
197        &self,
198        request: ScanRequest,
199    ) -> Result<ScanResponse, Self::Error>;
200
201    /// Fetch a collection of event records since a given commit hash.
202    async fn diff(
203        &self,
204        request: DiffRequest,
205    ) -> Result<DiffResponse, Self::Error>;
206
207    /// Patch an event log.
208    ///
209    /// If the request contains a commit hash then the remote will
210    /// attempt to rewind to the commit before applying the patch.
211    async fn patch(
212        &self,
213        request: PatchRequest,
214    ) -> Result<PatchResponse, Self::Error>;
215}