From 17a4ccdcbc37977cf7c4c17b8180a922936ee2f5 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 14 Sep 2020 19:32:43 +0300 Subject: [PATCH] melib/imap: perform reconnect on IDLE failure --- melib/src/backends/imap.rs | 11 +++++++++ melib/src/backends/imap/connection.rs | 12 +++++----- melib/src/backends/imap/watch.rs | 6 +++-- melib/src/error.rs | 4 +++- src/conf/accounts.rs | 34 +++++++++++++++++---------- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index f346d1649..b69569aa4 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -479,6 +479,17 @@ impl MailBackend for ImapType { main_conn.uid_store.is_online.lock().unwrap().1 = Err(err.clone()); } debug!("failure: {}", err.to_string()); + match timeout(timeout_dur, main_conn.connect()) + .await + .and_then(|res| res) + { + Err(err2) => { + debug!("reconnect attempt failed: {}", err2.to_string()); + } + Ok(()) => { + debug!("reconnect attempt succesful"); + } + } let account_hash = main_conn.uid_store.account_hash; main_conn.add_refresh_event(RefreshEvent { account_hash, diff --git a/melib/src/backends/imap/connection.rs b/melib/src/backends/imap/connection.rs index 5c17a9163..2f6a9ba47 100644 --- a/melib/src/backends/imap/connection.rs +++ b/melib/src/backends/imap/connection.rs @@ -984,7 +984,7 @@ pub struct ImapBlockingConnection { result: Vec, prev_res_length: usize, pub conn: ImapConnection, - err: Option, + err: Option, } impl From for ImapBlockingConnection { @@ -1004,8 +1004,8 @@ impl ImapBlockingConnection { self.conn } - pub fn err(&self) -> Option<&str> { - self.err.as_deref() + pub fn err(&mut self) -> Option { + self.err.take() } pub fn as_stream<'a>(&'a mut self) -> impl Future>> + 'a { @@ -1056,10 +1056,10 @@ async fn read( } *prev_failure = None; } - Err(e) => { + Err(_err) => { debug!(&conn.stream); - debug!(&e); - *err = Some(e.to_string()); + debug!(&_err); + *err = Some(Into::::into(_err).set_kind(crate::error::ErrorKind::Network)); *break_flag = true; *prev_failure = Some(Instant::now()); } diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index aaba948ff..07cf061c9 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -185,8 +185,10 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> { } } debug!("IDLE connection dropped"); - let err: &str = blockn.err().unwrap_or("Unknown reason."); - Err(MeliError::new(format!("IDLE connection dropped: {}", err))) + Err(blockn + .err() + .unwrap_or(MeliError::new("Unknown reason.").set_kind(crate::error::ErrorKind::Network)) + .set_summary("IDLE connection dropped".to_string())) } pub async fn examine_updates( diff --git a/melib/src/error.rs b/melib/src/error.rs index 945f92522..045ee3fde 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -205,7 +205,9 @@ impl Error for MeliError { impl From for MeliError { #[inline] fn from(kind: io::Error) -> MeliError { - MeliError::new(kind.to_string()).set_source(Some(Arc::new(kind))) + MeliError::new(kind.to_string()) + .set_summary(format!("{:?}", kind.kind())) + .set_source(Some(Arc::new(kind))) } } diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index 469b3c597..040f53dca 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -1355,24 +1355,19 @@ impl Account { let mut timeout = false; let mut drain: SmallVec<[std::time::Instant; 16]> = SmallVec::new(); const ONLINE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); - for (_instant, j) in self + for (_instant, _) in self .active_job_instants .range(..std::time::Instant::now() - ONLINE_TIMEOUT) { - if self.active_jobs.contains_key(j) { - debug!("timeout for {} {:?}", j, self.active_jobs[j]); - let req = self.active_jobs.remove(j).unwrap(); - self.sender - .send(ThreadEvent::UIEvent(UIEvent::StatusEvent( - StatusEvent::JobCanceled(*j), - ))) - .unwrap(); - timeout |= !req.is_watch(); - } drain.push(*_instant); } - for j in drain { - self.active_job_instants.remove(&j); + for inst in drain { + if let Some(j) = self.active_job_instants.remove(&inst) { + if let Some(req) = self.cancel_job(j) { + debug!("timeout for {} {:?}", j, &req); + timeout |= !req.is_watch(); + } + } } if self.is_online.is_err() && self @@ -2009,6 +2004,19 @@ impl Account { ))) .unwrap(); } + + pub fn cancel_job(&mut self, job_id: JobId) -> Option { + if let Some(req) = self.active_jobs.remove(&job_id) { + self.sender + .send(ThreadEvent::UIEvent(UIEvent::StatusEvent( + StatusEvent::JobCanceled(job_id), + ))) + .unwrap(); + Some(req) + } else { + None + } + } } impl Index<&MailboxHash> for Account {