diff --git a/src/configure.rs b/src/configure.rs index 80f6ddc7f..59809591a 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -565,14 +565,6 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result>, - /// IMAP UID resync request. - pub(crate) resync_request: AtomicBool, - /// Notify about new messages. /// /// This causes [`Context::wait_next_msgs`] to wake up. @@ -457,7 +454,6 @@ impl Context { scheduler: SchedulerState::new(), ratelimit: RwLock::new(Ratelimit::new(Duration::new(60, 0), 6.0)), // Allow at least 1 message every 10 seconds + a burst of 6. quota: RwLock::new(None), - resync_request: AtomicBool::new(false), new_msgs_notify, server_id: RwLock::new(None), metadata: RwLock::new(None), @@ -616,12 +612,6 @@ impl Context { Ok(()) } - pub(crate) async fn schedule_resync(&self) -> Result<()> { - self.resync_request.store(true, Ordering::Relaxed); - self.scheduler.interrupt_inbox().await; - Ok(()) - } - /// Returns a reference to the underlying SQL instance. /// /// Warning: this is only here for testing, not part of the public API. diff --git a/src/imap.rs b/src/imap.rs index 7826558af..a78643374 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -104,6 +104,12 @@ pub(crate) struct Imap { /// immediately after logging in or returning an error in response to LOGIN command /// due to internal server error. ratelimit: Ratelimit, + + /// IMAP UID resync request sender. + pub(crate) resync_request_sender: async_channel::Sender<()>, + + /// IMAP UID resync request receiver. + pub(crate) resync_request_receiver: async_channel::Receiver<()>, } #[derive(Debug)] @@ -254,6 +260,7 @@ impl Imap { oauth2: bool, idle_interrupt_receiver: Receiver<()>, ) -> Self { + let (resync_request_sender, resync_request_receiver) = async_channel::bounded(1); Imap { idle_interrupt_receiver, addr: addr.to_string(), @@ -268,6 +275,8 @@ impl Imap { conn_backoff_ms: 0, // 1 connection per minute + a burst of 2. ratelimit: Ratelimit::new(Duration::new(120, 0), 2.0), + resync_request_sender, + resync_request_receiver, } } @@ -392,6 +401,7 @@ impl Imap { match login_res { Ok(mut session) => { let capabilities = determine_capabilities(&mut session).await?; + let resync_request_sender = self.resync_request_sender.clone(); let session = if capabilities.can_compress { info!(context, "Enabling IMAP compression."); @@ -402,9 +412,9 @@ impl Imap { }) .await .context("Failed to enable IMAP compression")?; - Session::new(compressed_session, capabilities) + Session::new(compressed_session, capabilities, resync_request_sender) } else { - Session::new(session, capabilities) + Session::new(session, capabilities, resync_request_sender) }; // Store server ID in the context to display in account info. diff --git a/src/imap/select_folder.rs b/src/imap/select_folder.rs index 5796c4f0e..6023c8cff 100644 --- a/src/imap/select_folder.rs +++ b/src/imap/select_folder.rs @@ -206,7 +206,7 @@ impl ImapSession { "The server illegally decreased the uid_next of folder {folder:?} from {old_uid_next} to {new_uid_next} without changing validity ({new_uid_validity}), resyncing UIDs...", ); set_uid_next(context, folder, new_uid_next).await?; - context.schedule_resync().await?; + self.resync_request_sender.try_send(()).ok(); } // If UIDNEXT changed, there are new emails. @@ -243,7 +243,7 @@ impl ImapSession { .await?; if old_uid_validity != 0 || old_uid_next != 0 { - context.schedule_resync().await?; + self.resync_request_sender.try_send(()).ok(); } info!( context, diff --git a/src/imap/session.rs b/src/imap/session.rs index a633974d4..8cf0a17de 100644 --- a/src/imap/session.rs +++ b/src/imap/session.rs @@ -48,6 +48,8 @@ pub(crate) struct Session { /// /// Should be false if no folder is currently selected. pub new_mail: bool, + + pub resync_request_sender: async_channel::Sender<()>, } impl Deref for Session { @@ -68,6 +70,7 @@ impl Session { pub(crate) fn new( inner: ImapSession>, capabilities: Capabilities, + resync_request_sender: async_channel::Sender<()>, ) -> Self { Self { inner, @@ -77,6 +80,7 @@ impl Session { selected_folder_needs_expunge: false, last_full_folder_scan: Mutex::new(None), new_mail: false, + resync_request_sender, } } diff --git a/src/scheduler.rs b/src/scheduler.rs index 2a3537daf..daca1aeb1 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -1,7 +1,6 @@ use std::cmp; use std::iter::{self, once}; use std::num::NonZeroUsize; -use std::sync::atomic::Ordering; use anyhow::{Context as _, Error, Result, bail}; use async_channel::{self as channel, Receiver, Sender}; @@ -481,11 +480,10 @@ async fn inbox_fetch_idle(ctx: &Context, imap: &mut Imap, mut session: Session) } } - let resync_requested = ctx.resync_request.swap(false, Ordering::Relaxed); - if resync_requested { + if let Ok(()) = imap.resync_request_receiver.try_recv() { if let Err(err) = session.resync_folders(ctx).await { warn!(ctx, "Failed to resync folders: {:#}.", err); - ctx.resync_request.store(true, Ordering::Relaxed); + imap.resync_request_sender.try_send(()).ok(); } }