melib/imap: perform reconnect on IDLE failure

memfd
Manos Pitsidianakis 2020-09-14 19:32:43 +03:00
parent 670675edcc
commit 17a4ccdcbc
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
5 changed files with 45 additions and 22 deletions

View File

@ -479,6 +479,17 @@ impl MailBackend for ImapType {
main_conn.uid_store.is_online.lock().unwrap().1 = Err(err.clone()); main_conn.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())
.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; let account_hash = main_conn.uid_store.account_hash;
main_conn.add_refresh_event(RefreshEvent { main_conn.add_refresh_event(RefreshEvent {
account_hash, account_hash,

View File

@ -984,7 +984,7 @@ pub struct ImapBlockingConnection {
result: Vec<u8>, result: Vec<u8>,
prev_res_length: usize, prev_res_length: usize,
pub conn: ImapConnection, pub conn: ImapConnection,
err: Option<String>, err: Option<MeliError>,
} }
impl From<ImapConnection> for ImapBlockingConnection { impl From<ImapConnection> for ImapBlockingConnection {
@ -1004,8 +1004,8 @@ impl ImapBlockingConnection {
self.conn self.conn
} }
pub fn err(&self) -> Option<&str> { pub fn err(&mut self) -> Option<MeliError> {
self.err.as_deref() self.err.take()
} }
pub fn as_stream<'a>(&'a mut self) -> impl Future<Output = Option<Vec<u8>>> + 'a { pub fn as_stream<'a>(&'a mut self) -> impl Future<Output = Option<Vec<u8>>> + 'a {
@ -1056,10 +1056,10 @@ async fn read(
} }
*prev_failure = None; *prev_failure = None;
} }
Err(e) => { Err(_err) => {
debug!(&conn.stream); debug!(&conn.stream);
debug!(&e); debug!(&_err);
*err = Some(e.to_string()); *err = Some(Into::<MeliError>::into(_err).set_kind(crate::error::ErrorKind::Network));
*break_flag = true; *break_flag = true;
*prev_failure = Some(Instant::now()); *prev_failure = Some(Instant::now());
} }

View File

@ -185,8 +185,10 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> {
} }
} }
debug!("IDLE connection dropped"); debug!("IDLE connection dropped");
let err: &str = blockn.err().unwrap_or("Unknown reason."); Err(blockn
Err(MeliError::new(format!("IDLE connection dropped: {}", err))) .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(

View File

@ -205,7 +205,9 @@ impl Error for MeliError {
impl From<io::Error> for MeliError { impl From<io::Error> for MeliError {
#[inline] #[inline]
fn from(kind: io::Error) -> MeliError { 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)))
} }
} }

View File

@ -1355,24 +1355,19 @@ impl Account {
let mut timeout = false; let mut timeout = false;
let mut drain: SmallVec<[std::time::Instant; 16]> = SmallVec::new(); let mut drain: SmallVec<[std::time::Instant; 16]> = SmallVec::new();
const ONLINE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); const ONLINE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
for (_instant, j) in self for (_instant, _) in self
.active_job_instants .active_job_instants
.range(..std::time::Instant::now() - ONLINE_TIMEOUT) .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); drain.push(*_instant);
} }
for j in drain { for inst in drain {
self.active_job_instants.remove(&j); 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() if self.is_online.is_err()
&& self && self
@ -2009,6 +2004,19 @@ impl Account {
))) )))
.unwrap(); .unwrap();
} }
pub fn cancel_job(&mut self, job_id: JobId) -> Option<JobRequest> {
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 { impl Index<&MailboxHash> for Account {