email/sync/
pool.rs

1use std::{collections::BTreeSet, sync::Arc};
2
3#[doc(inline)]
4pub use super::{Error, Result};
5use super::{SyncDestination, SyncEventHandler};
6use crate::{
7    backend::{
8        context::{BackendContext, BackendContextBuilder},
9        Backend, BackendBuilder,
10    },
11    email::sync::hunk::EmailSyncHunk,
12    envelope::sync::config::EnvelopeSyncFilters,
13    flag::sync::config::FlagSyncPermissions,
14    folder::sync::{
15        config::{FolderSyncPermissions, FolderSyncStrategy},
16        hunk::FolderSyncHunk,
17        patch::FolderSyncPatches,
18    },
19    maildir::{MaildirContextBuilder, MaildirContextSync},
20    message::sync::config::MessageSyncPermissions,
21    AnyResult,
22};
23
24#[derive(Clone, Default)]
25pub struct SyncPoolConfig {
26    pub left_folder_permissions: Option<FolderSyncPermissions>,
27    pub left_flag_permissions: Option<FlagSyncPermissions>,
28    pub left_message_permissions: Option<MessageSyncPermissions>,
29    pub right_folder_permissions: Option<FolderSyncPermissions>,
30    pub right_flag_permissions: Option<FlagSyncPermissions>,
31    pub right_message_permissions: Option<MessageSyncPermissions>,
32    pub pool_size: Option<usize>,
33    pub folder_filters: Option<FolderSyncStrategy>,
34    pub envelope_filters: Option<EnvelopeSyncFilters>,
35    pub handler: Option<Arc<SyncEventHandler>>,
36    pub dry_run: Option<bool>,
37}
38
39#[derive(Clone)]
40pub struct SyncPoolContextBuilder<L, R>
41where
42    L: BackendContextBuilder,
43    R: BackendContextBuilder,
44{
45    config: SyncPoolConfig,
46    left_cache_builder: BackendBuilder<MaildirContextBuilder>,
47    left_builder: BackendBuilder<L>,
48    right_cache_builder: BackendBuilder<MaildirContextBuilder>,
49    right_builder: BackendBuilder<R>,
50}
51
52impl<L, R> SyncPoolContextBuilder<L, R>
53where
54    L: BackendContextBuilder,
55    R: BackendContextBuilder,
56{
57    pub fn new(
58        config: SyncPoolConfig,
59        left_cache_builder: BackendBuilder<MaildirContextBuilder>,
60        left_builder: BackendBuilder<L>,
61        right_cache_builder: BackendBuilder<MaildirContextBuilder>,
62        right_builder: BackendBuilder<R>,
63    ) -> Self {
64        Self {
65            config,
66            left_cache_builder,
67            left_builder,
68            right_cache_builder,
69            right_builder,
70        }
71    }
72
73    pub async fn build(self) -> AnyResult<SyncPoolContext<L::Context, R::Context>> {
74        let left_folder_permissions = self
75            .config
76            .left_folder_permissions
77            .clone()
78            .or_else(|| {
79                self.left_builder
80                    .account_config
81                    .folder
82                    .as_ref()
83                    .and_then(|c| c.sync.as_ref())
84                    .map(|c| c.permissions.clone())
85            })
86            .unwrap_or_default();
87
88        let left_flag_permissions = self
89            .config
90            .left_flag_permissions
91            .clone()
92            .or_else(|| {
93                self.left_builder
94                    .account_config
95                    .flag
96                    .as_ref()
97                    .and_then(|c| c.sync.as_ref())
98                    .map(|c| c.permissions.clone())
99            })
100            .unwrap_or_default();
101
102        let left_message_permissions = self
103            .config
104            .left_message_permissions
105            .clone()
106            .or_else(|| {
107                self.left_builder
108                    .account_config
109                    .message
110                    .as_ref()
111                    .and_then(|c| c.sync.as_ref())
112                    .map(|c| c.permissions.clone())
113            })
114            .unwrap_or_default();
115
116        let right_folder_permissions = self
117            .config
118            .right_folder_permissions
119            .clone()
120            .or_else(|| {
121                self.right_builder
122                    .account_config
123                    .folder
124                    .as_ref()
125                    .and_then(|c| c.sync.as_ref())
126                    .map(|c| c.permissions.clone())
127            })
128            .unwrap_or_default();
129
130        let right_flag_permissions = self
131            .config
132            .right_flag_permissions
133            .clone()
134            .or_else(|| {
135                self.right_builder
136                    .account_config
137                    .flag
138                    .as_ref()
139                    .and_then(|c| c.sync.as_ref())
140                    .map(|c| c.permissions.clone())
141            })
142            .unwrap_or_default();
143
144        let right_message_permissions = self
145            .config
146            .right_message_permissions
147            .clone()
148            .or_else(|| {
149                self.right_builder
150                    .account_config
151                    .message
152                    .as_ref()
153                    .and_then(|c| c.sync.as_ref())
154                    .map(|c| c.permissions.clone())
155            })
156            .unwrap_or_default();
157
158        let folder_filters = self
159            .config
160            .folder_filters
161            .clone()
162            .or_else(|| {
163                self.right_builder
164                    .account_config
165                    .folder
166                    .as_ref()
167                    .and_then(|c| c.sync.as_ref())
168                    .map(|c| c.filter.clone())
169            })
170            .unwrap_or_default();
171
172        let envelope_filters = self
173            .config
174            .envelope_filters
175            .clone()
176            .or_else(|| {
177                self.right_builder
178                    .account_config
179                    .envelope
180                    .as_ref()
181                    .and_then(|c| c.sync.as_ref())
182                    .map(|c| c.filter.clone())
183            })
184            .unwrap_or_default();
185
186        let (left_cache, left, right_cache, right) = tokio::try_join!(
187            self.left_cache_builder.build(),
188            self.left_builder.build(),
189            self.right_cache_builder.build(),
190            self.right_builder.build(),
191        )?;
192
193        Ok(SyncPoolContext {
194            left_cache,
195            left,
196            left_folder_permissions,
197            left_flag_permissions,
198            left_message_permissions,
199            right_cache,
200            right,
201            right_folder_permissions,
202            right_flag_permissions,
203            right_message_permissions,
204            folder_filters,
205            envelope_filters,
206            handler: self.config.handler,
207            dry_run: self.config.dry_run.unwrap_or_default(),
208        })
209    }
210}
211
212pub struct SyncPoolContext<L: BackendContext, R: BackendContext> {
213    pub left_cache: Backend<MaildirContextSync>,
214    pub left: Backend<L>,
215    pub right_cache: Backend<MaildirContextSync>,
216    pub right: Backend<R>,
217    pub left_folder_permissions: FolderSyncPermissions,
218    pub left_flag_permissions: FlagSyncPermissions,
219    pub left_message_permissions: MessageSyncPermissions,
220    pub right_folder_permissions: FolderSyncPermissions,
221    pub right_flag_permissions: FlagSyncPermissions,
222    pub right_message_permissions: MessageSyncPermissions,
223    pub folder_filters: FolderSyncStrategy,
224    pub envelope_filters: EnvelopeSyncFilters,
225    pub handler: Option<Arc<SyncEventHandler>>,
226    pub dry_run: bool,
227}
228
229impl<L: BackendContext, R: BackendContext> SyncPoolContext<L, R> {
230    pub fn apply_folder_permissions(&self, patch: &mut FolderSyncPatches) {
231        use FolderSyncHunk::*;
232        use SyncDestination::*;
233
234        for (_, patch) in patch.iter_mut() {
235            patch.retain(|hunk| match hunk {
236                Create(_, Left) | Cache(_, Left) => self.left_folder_permissions.create,
237                Create(_, Right) | Cache(_, Right) => self.right_folder_permissions.create,
238                Delete(_, Left) | Uncache(_, Left) => self.left_folder_permissions.delete,
239                Delete(_, Right) | Uncache(_, Right) => self.right_folder_permissions.delete,
240            });
241        }
242    }
243
244    pub fn apply_flag_and_message_permissions(&self, patch: &mut BTreeSet<EmailSyncHunk>) {
245        use EmailSyncHunk::*;
246        use SyncDestination::*;
247
248        patch.retain(|hunk| match hunk {
249            GetThenCache(_, _, Left) => self.left_message_permissions.create,
250            GetThenCache(_, _, Right) => self.right_message_permissions.create,
251            CopyThenCache(_, _, _, Left, _) => self.left_message_permissions.create,
252            CopyThenCache(_, _, _, Right, _) => self.right_message_permissions.create,
253            UpdateCachedFlags(_, _, Left) => self.left_flag_permissions.update,
254            UpdateCachedFlags(_, _, Right) => self.right_flag_permissions.update,
255            UpdateFlags(_, _, Left) => self.left_flag_permissions.update,
256            UpdateFlags(_, _, Right) => self.right_flag_permissions.update,
257            Uncache(_, _, Left) | Delete(_, _, Left) => self.left_message_permissions.delete,
258            Uncache(_, _, Right) | Delete(_, _, Right) => self.right_message_permissions.delete,
259        });
260    }
261}