melib/imap: always retry connection in watch()

memfd
Manos Pitsidianakis 2020-09-15 12:59:31 +03:00
parent 67c722958b
commit 0e2641f7ed
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 44 additions and 40 deletions

View File

@ -444,7 +444,7 @@ impl MailBackend for ImapType {
} }
fn watch(&self) -> ResultFuture<()> { 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 main_conn = self.connection.clone();
let uid_store = self.uid_store.clone(); let uid_store = self.uid_store.clone();
let has_idle: bool = match self.server_conf.protocol { let has_idle: bool = match self.server_conf.protocol {
@ -462,24 +462,27 @@ impl MailBackend for ImapType {
}; };
Ok(Box::pin(async move { Ok(Box::pin(async move {
debug!(has_idle); debug!(has_idle);
let main_conn2 = main_conn.clone(); while let Err(err) = if has_idle {
let timeout_dur = uid_store.timeout; idle(ImapWatchKit {
let kit = ImapWatchKit { conn: ImapConnection::new_connection(&server_conf, uid_store.clone()),
conn, main_conn: main_conn.clone(),
main_conn, uid_store: uid_store.clone(),
uid_store, })
}; .await
if let Err(err) = if has_idle {
idle(kit).await
} else { } 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() { 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()); debug!("failure: {}", err.to_string());
match timeout(timeout_dur, main_conn.connect()) match timeout(uid_store.timeout, main_conn_lck.connect())
.await .await
.and_then(|res| res) .and_then(|res| res)
{ {
@ -488,10 +491,11 @@ impl MailBackend for ImapType {
} }
Ok(()) => { Ok(()) => {
debug!("reconnect attempt succesful"); debug!("reconnect attempt succesful");
continue;
} }
} }
let account_hash = main_conn.uid_store.account_hash; let account_hash = uid_store.account_hash;
main_conn.add_refresh_event(RefreshEvent { main_conn_lck.add_refresh_event(RefreshEvent {
account_hash, account_hash,
mailbox_hash: 0, mailbox_hash: 0,
kind: RefreshEventKind::Failure(err.clone()), kind: RefreshEventKind::Failure(err.clone()),

View File

@ -113,30 +113,35 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> {
}; };
conn.send_command(b"IDLE").await?; conn.send_command(b"IDLE").await?;
let mut blockn = ImapBlockingConnection::from(conn); let mut blockn = ImapBlockingConnection::from(conn);
let mut beat = std::time::Instant::now();
let mut watch = 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 */ /* 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 */ /* duration interval to check other mailboxes for changes */
const _5_MINS: std::time::Duration = std::time::Duration::from_secs(5 * 60); 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(); 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 { if now.duration_since(watch) >= _5_MINS {
/* Time to poll all inboxes */ /* Time to poll all inboxes */
let mut conn = timeout(uid_store.timeout, main_conn.lock()).await?; 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?; 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( pub async fn examine_updates(