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());
}
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,

View File

@ -984,7 +984,7 @@ pub struct ImapBlockingConnection {
result: Vec<u8>,
prev_res_length: usize,
pub conn: ImapConnection,
err: Option<String>,
err: Option<MeliError>,
}
impl From<ImapConnection> 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<MeliError> {
self.err.take()
}
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;
}
Err(e) => {
Err(_err) => {
debug!(&conn.stream);
debug!(&e);
*err = Some(e.to_string());
debug!(&_err);
*err = Some(Into::<MeliError>::into(_err).set_kind(crate::error::ErrorKind::Network));
*break_flag = true;
*prev_failure = Some(Instant::now());
}

View File

@ -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(

View File

@ -205,7 +205,9 @@ impl Error for MeliError {
impl From<io::Error> 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)))
}
}

View File

@ -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<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 {