From 0e2641f7ed8bdde9ef87923b049f3fd1ebd382d0 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Tue, 15 Sep 2020 12:59:31 +0300 Subject: [PATCH] melib/imap: always retry connection in watch() --- melib/src/backends/imap.rs | 36 +++++++++++++----------- melib/src/backends/imap/watch.rs | 48 ++++++++++++++++---------------- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index a9ca5d5c..cb4d994b 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -444,7 +444,7 @@ impl MailBackend for ImapType { } fn watch(&self) -> ResultFuture<()> { - let conn = ImapConnection::new_connection(&self.server_conf, self.uid_store.clone()); + let server_conf = self.server_conf.clone(); let main_conn = self.connection.clone(); let uid_store = self.uid_store.clone(); let has_idle: bool = match self.server_conf.protocol { @@ -462,24 +462,27 @@ impl MailBackend for ImapType { }; Ok(Box::pin(async move { debug!(has_idle); - let main_conn2 = main_conn.clone(); - let timeout_dur = uid_store.timeout; - let kit = ImapWatchKit { - conn, - main_conn, - uid_store, - }; - if let Err(err) = if has_idle { - idle(kit).await + while let Err(err) = if has_idle { + idle(ImapWatchKit { + conn: ImapConnection::new_connection(&server_conf, uid_store.clone()), + main_conn: main_conn.clone(), + uid_store: uid_store.clone(), + }) + .await } else { - poll_with_examine(kit).await + poll_with_examine(ImapWatchKit { + conn: ImapConnection::new_connection(&server_conf, uid_store.clone()), + main_conn: main_conn.clone(), + uid_store: uid_store.clone(), + }) + .await } { - let mut main_conn = timeout(timeout_dur, main_conn2.lock()).await?; + let mut main_conn_lck = timeout(uid_store.timeout, main_conn.lock()).await?; if err.kind.is_network() { - main_conn.uid_store.is_online.lock().unwrap().1 = Err(err.clone()); + uid_store.is_online.lock().unwrap().1 = Err(err.clone()); } debug!("failure: {}", err.to_string()); - match timeout(timeout_dur, main_conn.connect()) + match timeout(uid_store.timeout, main_conn_lck.connect()) .await .and_then(|res| res) { @@ -488,10 +491,11 @@ impl MailBackend for ImapType { } Ok(()) => { debug!("reconnect attempt succesful"); + continue; } } - let account_hash = main_conn.uid_store.account_hash; - main_conn.add_refresh_event(RefreshEvent { + let account_hash = uid_store.account_hash; + main_conn_lck.add_refresh_event(RefreshEvent { account_hash, mailbox_hash: 0, kind: RefreshEventKind::Failure(err.clone()), diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index 07cf061c..7b6f09ed 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -113,30 +113,35 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> { }; conn.send_command(b"IDLE").await?; let mut blockn = ImapBlockingConnection::from(conn); - let mut beat = std::time::Instant::now(); let mut watch = std::time::Instant::now(); - /* duration interval before IMAP timeouts */ - const _35_MINS: std::time::Duration = std::time::Duration::from_secs(35 * 60); /* duration interval to send heartbeat */ - const _26_MINS: std::time::Duration = std::time::Duration::from_secs(26 * 60); + const _10_MINS: std::time::Duration = std::time::Duration::from_secs(10 * 60); /* duration interval to check other mailboxes for changes */ const _5_MINS: std::time::Duration = std::time::Duration::from_secs(5 * 60); - while let Some(line) = timeout(Some(_35_MINS), blockn.as_stream()).await? { + loop { + let line = match timeout(Some(_10_MINS), blockn.as_stream()).await { + Ok(Some(line)) => line, + Ok(None) => { + debug!("IDLE connection dropped: {:?}", &blockn.err()); + blockn.conn.connect().await?; + let mut main_conn_lck = timeout(uid_store.timeout, main_conn.lock()).await?; + main_conn_lck.connect().await?; + continue; + } + Err(_) => { + /* Timeout */ + blockn.conn.send_raw(b"DONE").await?; + blockn + .conn + .read_response(&mut response, RequiredResponses::empty()) + .await?; + blockn.conn.send_command(b"IDLE").await?; + let mut main_conn_lck = timeout(uid_store.timeout, main_conn.lock()).await?; + main_conn_lck.connect().await?; + continue; + } + }; let now = std::time::Instant::now(); - if now.duration_since(beat) >= _26_MINS { - let mut main_conn_lck = timeout(uid_store.timeout, main_conn.lock()).await?; - blockn.conn.send_raw(b"DONE").await?; - blockn - .conn - .read_response(&mut response, RequiredResponses::empty()) - .await?; - blockn.conn.send_command(b"IDLE").await?; - main_conn_lck.send_command(b"NOOP").await?; - main_conn_lck - .read_response(&mut response, RequiredResponses::empty()) - .await?; - beat = now; - } if now.duration_since(watch) >= _5_MINS { /* Time to poll all inboxes */ let mut conn = timeout(uid_store.timeout, main_conn.lock()).await?; @@ -184,11 +189,6 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> { blockn.conn.send_command(b"IDLE").await?; } } - debug!("IDLE connection dropped"); - 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(