mirror of
https://github.com/chatmail/core.git
synced 2026-05-17 05:46:30 +03:00
scheduler: make Scheduler stateless
Scheduler has no Stopped state anymore. If Scheduler exists, it is always started. Scheduler is stopped via Scheduler.stop(), which consumes Scheduler and cannot fail.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
- send normal messages with higher priority than MDNs #3243
|
- send normal messages with higher priority than MDNs #3243
|
||||||
|
- make Scheduler stateless #3302
|
||||||
|
|
||||||
|
|
||||||
## 1.80.0
|
## 1.80.0
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ impl Context {
|
|||||||
use futures::future::FutureExt;
|
use futures::future::FutureExt;
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
!self.scheduler.read().await.is_running(),
|
self.scheduler.read().await.is_none(),
|
||||||
"cannot configure, already running"
|
"cannot configure, already running"
|
||||||
);
|
);
|
||||||
ensure!(
|
ensure!(
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub struct InnerContext {
|
|||||||
pub(crate) translated_stockstrings: RwLock<HashMap<usize, String>>,
|
pub(crate) translated_stockstrings: RwLock<HashMap<usize, String>>,
|
||||||
pub(crate) events: Events,
|
pub(crate) events: Events,
|
||||||
|
|
||||||
pub(crate) scheduler: RwLock<Scheduler>,
|
pub(crate) scheduler: RwLock<Option<Scheduler>>,
|
||||||
|
|
||||||
/// Recently loaded quota information, if any.
|
/// Recently loaded quota information, if any.
|
||||||
/// Set to `None` if quota was never tried to load.
|
/// Set to `None` if quota was never tried to load.
|
||||||
@@ -173,7 +173,7 @@ impl Context {
|
|||||||
wrong_pw_warning_mutex: Mutex::new(()),
|
wrong_pw_warning_mutex: Mutex::new(()),
|
||||||
translated_stockstrings: RwLock::new(HashMap::new()),
|
translated_stockstrings: RwLock::new(HashMap::new()),
|
||||||
events: Events::default(),
|
events: Events::default(),
|
||||||
scheduler: RwLock::new(Scheduler::Stopped),
|
scheduler: RwLock::new(None),
|
||||||
quota: RwLock::new(None),
|
quota: RwLock::new(None),
|
||||||
creation_time: std::time::SystemTime::now(),
|
creation_time: std::time::SystemTime::now(),
|
||||||
last_full_folder_scan: Mutex::new(None),
|
last_full_folder_scan: Mutex::new(None),
|
||||||
@@ -195,8 +195,12 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!(self, "starting IO");
|
info!(self, "starting IO");
|
||||||
if let Err(err) = self.inner.scheduler.write().await.start(self.clone()).await {
|
let mut lock = self.inner.scheduler.write().await;
|
||||||
error!(self, "Failed to start IO: {}", err)
|
if lock.is_none() {
|
||||||
|
match Scheduler::start(self.clone()).await {
|
||||||
|
Err(err) => error!(self, "Failed to start IO: {}", err),
|
||||||
|
Ok(scheduler) => *lock = Some(scheduler),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,8 +213,8 @@ impl Context {
|
|||||||
// which will emit the below event(s)
|
// which will emit the below event(s)
|
||||||
info!(self, "stopping IO");
|
info!(self, "stopping IO");
|
||||||
|
|
||||||
if let Err(err) = self.inner.stop_io().await {
|
if let Some(scheduler) = self.inner.scheduler.write().await.take() {
|
||||||
warn!(self, "failed to stop IO: {}", err);
|
scheduler.stop(self).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,13 +646,6 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerContext {
|
|
||||||
async fn stop_io(&self) -> Result<()> {
|
|
||||||
self.scheduler.write().await.stop().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for RunningState {
|
impl Default for RunningState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
RunningState {
|
RunningState {
|
||||||
|
|||||||
@@ -445,8 +445,8 @@ async fn import_backup(
|
|||||||
"Cannot import backups to accounts in use."
|
"Cannot import backups to accounts in use."
|
||||||
);
|
);
|
||||||
ensure!(
|
ensure!(
|
||||||
!context.scheduler.read().await.is_running(),
|
context.scheduler.read().await.is_none(),
|
||||||
"cannot import backup, IO already running"
|
"cannot import backup, IO is running"
|
||||||
);
|
);
|
||||||
|
|
||||||
let backup_file = File::open(backup_to_import).await?;
|
let backup_file = File::open(backup_to_import).await?;
|
||||||
@@ -563,8 +563,8 @@ async fn export_backup(context: &Context, dir: &Path, passphrase: String) -> Res
|
|||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
!context.scheduler.read().await.is_running(),
|
context.scheduler.read().await.is_none(),
|
||||||
"cannot export backup, IO already running"
|
"cannot export backup, IO is running"
|
||||||
);
|
);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
|
|||||||
213
src/scheduler.rs
213
src/scheduler.rs
@@ -2,7 +2,7 @@ use anyhow::{bail, Context as _, Result};
|
|||||||
use async_std::prelude::*;
|
use async_std::prelude::*;
|
||||||
use async_std::{
|
use async_std::{
|
||||||
channel::{self, Receiver, Sender},
|
channel::{self, Receiver, Sender},
|
||||||
task,
|
future, task,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
@@ -23,54 +23,62 @@ pub(crate) mod connectivity;
|
|||||||
|
|
||||||
/// Job and connection scheduler.
|
/// Job and connection scheduler.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
pub(crate) struct Scheduler {
|
||||||
pub(crate) enum Scheduler {
|
inbox: ImapConnectionState,
|
||||||
Stopped,
|
inbox_handle: task::JoinHandle<()>,
|
||||||
Running {
|
mvbox: ImapConnectionState,
|
||||||
inbox: ImapConnectionState,
|
mvbox_handle: Option<task::JoinHandle<()>>,
|
||||||
inbox_handle: Option<task::JoinHandle<()>>,
|
sentbox: ImapConnectionState,
|
||||||
mvbox: ImapConnectionState,
|
sentbox_handle: Option<task::JoinHandle<()>>,
|
||||||
mvbox_handle: Option<task::JoinHandle<()>>,
|
smtp: SmtpConnectionState,
|
||||||
sentbox: ImapConnectionState,
|
smtp_handle: task::JoinHandle<()>,
|
||||||
sentbox_handle: Option<task::JoinHandle<()>>,
|
ephemeral_handle: task::JoinHandle<()>,
|
||||||
smtp: SmtpConnectionState,
|
ephemeral_interrupt_send: Sender<()>,
|
||||||
smtp_handle: Option<task::JoinHandle<()>>,
|
location_handle: task::JoinHandle<()>,
|
||||||
ephemeral_handle: Option<task::JoinHandle<()>>,
|
location_interrupt_send: Sender<()>,
|
||||||
ephemeral_interrupt_send: Sender<()>,
|
|
||||||
location_handle: Option<task::JoinHandle<()>>,
|
|
||||||
location_interrupt_send: Sender<()>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
/// Indicate that the network likely has come back.
|
/// Indicate that the network likely has come back.
|
||||||
pub async fn maybe_network(&self) {
|
pub async fn maybe_network(&self) {
|
||||||
let lock = self.scheduler.read().await;
|
let lock = self.scheduler.read().await;
|
||||||
lock.maybe_network().await;
|
if let Some(scheduler) = &*lock {
|
||||||
|
scheduler.maybe_network().await;
|
||||||
|
}
|
||||||
connectivity::idle_interrupted(lock).await;
|
connectivity::idle_interrupted(lock).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicate that the network likely is lost.
|
/// Indicate that the network likely is lost.
|
||||||
pub async fn maybe_network_lost(&self) {
|
pub async fn maybe_network_lost(&self) {
|
||||||
let lock = self.scheduler.read().await;
|
let lock = self.scheduler.read().await;
|
||||||
lock.maybe_network_lost().await;
|
if let Some(scheduler) = &*lock {
|
||||||
|
scheduler.maybe_network_lost().await;
|
||||||
|
}
|
||||||
connectivity::maybe_network_lost(self, lock).await;
|
connectivity::maybe_network_lost(self, lock).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn interrupt_inbox(&self, info: InterruptInfo) {
|
pub(crate) async fn interrupt_inbox(&self, info: InterruptInfo) {
|
||||||
self.scheduler.read().await.interrupt_inbox(info).await;
|
if let Some(scheduler) = &*self.scheduler.read().await {
|
||||||
|
scheduler.interrupt_inbox(info).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn interrupt_smtp(&self, info: InterruptInfo) {
|
pub(crate) async fn interrupt_smtp(&self, info: InterruptInfo) {
|
||||||
self.scheduler.read().await.interrupt_smtp(info).await;
|
if let Some(scheduler) = &*self.scheduler.read().await {
|
||||||
|
scheduler.interrupt_smtp(info).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn interrupt_ephemeral_task(&self) {
|
pub(crate) async fn interrupt_ephemeral_task(&self) {
|
||||||
self.scheduler.read().await.interrupt_ephemeral_task().await;
|
if let Some(scheduler) = &*self.scheduler.read().await {
|
||||||
|
scheduler.interrupt_ephemeral_task().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn interrupt_location(&self) {
|
pub(crate) async fn interrupt_location(&self) {
|
||||||
self.scheduler.read().await.interrupt_location().await;
|
if let Some(scheduler) = &*self.scheduler.read().await {
|
||||||
|
scheduler.interrupt_location().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,12 +364,8 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
/// Start the scheduler, returns error if it is already running.
|
/// Start the scheduler.
|
||||||
pub async fn start(&mut self, ctx: Context) -> Result<()> {
|
pub async fn start(ctx: Context) -> Result<Self> {
|
||||||
if self.is_running() {
|
|
||||||
bail!("scheduler is already started");
|
|
||||||
}
|
|
||||||
|
|
||||||
let (mvbox, mvbox_handlers) = ImapConnectionState::new(&ctx).await?;
|
let (mvbox, mvbox_handlers) = ImapConnectionState::new(&ctx).await?;
|
||||||
let (sentbox, sentbox_handlers) = ImapConnectionState::new(&ctx).await?;
|
let (sentbox, sentbox_handlers) = ImapConnectionState::new(&ctx).await?;
|
||||||
let (smtp, smtp_handlers) = SmtpConnectionState::new();
|
let (smtp, smtp_handlers) = SmtpConnectionState::new();
|
||||||
@@ -378,9 +382,7 @@ impl Scheduler {
|
|||||||
|
|
||||||
let inbox_handle = {
|
let inbox_handle = {
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
Some(task::spawn(async move {
|
task::spawn(async move { inbox_loop(ctx, inbox_start_send, inbox_handlers).await })
|
||||||
inbox_loop(ctx, inbox_start_send, inbox_handlers).await
|
|
||||||
}))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if ctx.should_watch_mvbox().await? {
|
if ctx.should_watch_mvbox().await? {
|
||||||
@@ -431,26 +433,24 @@ impl Scheduler {
|
|||||||
|
|
||||||
let smtp_handle = {
|
let smtp_handle = {
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
Some(task::spawn(async move {
|
task::spawn(async move { smtp_loop(ctx, smtp_start_send, smtp_handlers).await })
|
||||||
smtp_loop(ctx, smtp_start_send, smtp_handlers).await
|
|
||||||
}))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ephemeral_handle = {
|
let ephemeral_handle = {
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
Some(task::spawn(async move {
|
task::spawn(async move {
|
||||||
ephemeral::ephemeral_loop(&ctx, ephemeral_interrupt_recv).await;
|
ephemeral::ephemeral_loop(&ctx, ephemeral_interrupt_recv).await;
|
||||||
}))
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let location_handle = {
|
let location_handle = {
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
Some(task::spawn(async move {
|
task::spawn(async move {
|
||||||
location::location_loop(&ctx, location_interrupt_recv).await;
|
location::location_loop(&ctx, location_interrupt_recv).await;
|
||||||
}))
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
*self = Scheduler::Running {
|
let res = Self {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
@@ -477,14 +477,10 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!(ctx, "scheduler is running");
|
info!(ctx, "scheduler is running");
|
||||||
Ok(())
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn maybe_network(&self) {
|
async fn maybe_network(&self) {
|
||||||
if !self.is_running() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.interrupt_inbox(InterruptInfo::new(true))
|
self.interrupt_inbox(InterruptInfo::new(true))
|
||||||
.join(self.interrupt_mvbox(InterruptInfo::new(true)))
|
.join(self.interrupt_mvbox(InterruptInfo::new(true)))
|
||||||
.join(self.interrupt_sentbox(InterruptInfo::new(true)))
|
.join(self.interrupt_sentbox(InterruptInfo::new(true)))
|
||||||
@@ -493,10 +489,6 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn maybe_network_lost(&self) {
|
async fn maybe_network_lost(&self) {
|
||||||
if !self.is_running() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.interrupt_inbox(InterruptInfo::new(false))
|
self.interrupt_inbox(InterruptInfo::new(false))
|
||||||
.join(self.interrupt_mvbox(InterruptInfo::new(false)))
|
.join(self.interrupt_mvbox(InterruptInfo::new(false)))
|
||||||
.join(self.interrupt_sentbox(InterruptInfo::new(false)))
|
.join(self.interrupt_sentbox(InterruptInfo::new(false)))
|
||||||
@@ -505,109 +497,64 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_inbox(&self, info: InterruptInfo) {
|
async fn interrupt_inbox(&self, info: InterruptInfo) {
|
||||||
if let Scheduler::Running { ref inbox, .. } = self {
|
self.inbox.interrupt(info).await;
|
||||||
inbox.interrupt(info).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_mvbox(&self, info: InterruptInfo) {
|
async fn interrupt_mvbox(&self, info: InterruptInfo) {
|
||||||
if let Scheduler::Running { ref mvbox, .. } = self {
|
self.mvbox.interrupt(info).await;
|
||||||
mvbox.interrupt(info).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_sentbox(&self, info: InterruptInfo) {
|
async fn interrupt_sentbox(&self, info: InterruptInfo) {
|
||||||
if let Scheduler::Running { ref sentbox, .. } = self {
|
self.sentbox.interrupt(info).await;
|
||||||
sentbox.interrupt(info).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_smtp(&self, info: InterruptInfo) {
|
async fn interrupt_smtp(&self, info: InterruptInfo) {
|
||||||
if let Scheduler::Running { ref smtp, .. } = self {
|
self.smtp.interrupt(info).await;
|
||||||
smtp.interrupt(info).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_ephemeral_task(&self) {
|
async fn interrupt_ephemeral_task(&self) {
|
||||||
if let Scheduler::Running {
|
self.ephemeral_interrupt_send.try_send(()).ok();
|
||||||
ref ephemeral_interrupt_send,
|
|
||||||
..
|
|
||||||
} = self
|
|
||||||
{
|
|
||||||
ephemeral_interrupt_send.try_send(()).ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_location(&self) {
|
async fn interrupt_location(&self) {
|
||||||
if let Scheduler::Running {
|
self.location_interrupt_send.try_send(()).ok();
|
||||||
ref location_interrupt_send,
|
|
||||||
..
|
|
||||||
} = self
|
|
||||||
{
|
|
||||||
location_interrupt_send.try_send(()).ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Halt the scheduler.
|
/// Halt the scheduler.
|
||||||
pub(crate) async fn stop(&mut self) -> Result<()> {
|
///
|
||||||
match self {
|
/// It consumes the scheduler and never fails to stop it. In the worst case, long-running tasks
|
||||||
Scheduler::Stopped => {
|
/// are forcefully terminated if they cannot shutdown within the timeout.
|
||||||
bail!("scheduler is already stopped");
|
pub(crate) async fn stop(mut self, context: &Context) {
|
||||||
}
|
// Send stop signals to tasks so they can shutdown cleanly.
|
||||||
Scheduler::Running {
|
self.inbox.stop().await.ok_or_log(context);
|
||||||
inbox,
|
if self.mvbox_handle.is_some() {
|
||||||
inbox_handle,
|
self.mvbox.stop().await.ok_or_log(context);
|
||||||
mvbox,
|
|
||||||
mvbox_handle,
|
|
||||||
sentbox,
|
|
||||||
sentbox_handle,
|
|
||||||
smtp,
|
|
||||||
smtp_handle,
|
|
||||||
ephemeral_handle,
|
|
||||||
location_handle,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
if inbox_handle.is_some() {
|
|
||||||
inbox.stop().await?;
|
|
||||||
}
|
|
||||||
if mvbox_handle.is_some() {
|
|
||||||
mvbox.stop().await?;
|
|
||||||
}
|
|
||||||
if sentbox_handle.is_some() {
|
|
||||||
sentbox.stop().await?;
|
|
||||||
}
|
|
||||||
if smtp_handle.is_some() {
|
|
||||||
smtp.stop().await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(handle) = inbox_handle.take() {
|
|
||||||
handle.await;
|
|
||||||
}
|
|
||||||
if let Some(handle) = mvbox_handle.take() {
|
|
||||||
handle.await;
|
|
||||||
}
|
|
||||||
if let Some(handle) = sentbox_handle.take() {
|
|
||||||
handle.await;
|
|
||||||
}
|
|
||||||
if let Some(handle) = smtp_handle.take() {
|
|
||||||
handle.await;
|
|
||||||
}
|
|
||||||
if let Some(handle) = ephemeral_handle.take() {
|
|
||||||
handle.cancel().await;
|
|
||||||
}
|
|
||||||
if let Some(handle) = location_handle.take() {
|
|
||||||
handle.cancel().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
*self = Scheduler::Stopped;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if self.sentbox_handle.is_some() {
|
||||||
|
self.sentbox.stop().await.ok_or_log(context);
|
||||||
|
}
|
||||||
|
self.smtp.stop().await.ok_or_log(context);
|
||||||
|
|
||||||
/// Check if the scheduler is running.
|
// Actually shutdown tasks.
|
||||||
pub fn is_running(&self) -> bool {
|
let timeout_duration = std::time::Duration::from_secs(30);
|
||||||
matches!(self, Scheduler::Running { .. })
|
future::timeout(timeout_duration, self.inbox_handle)
|
||||||
|
.await
|
||||||
|
.ok_or_log(context);
|
||||||
|
if let Some(mvbox_handle) = self.mvbox_handle.take() {
|
||||||
|
future::timeout(timeout_duration, mvbox_handle)
|
||||||
|
.await
|
||||||
|
.ok_or_log(context);
|
||||||
|
}
|
||||||
|
if let Some(sentbox_handle) = self.sentbox_handle.take() {
|
||||||
|
future::timeout(timeout_duration, sentbox_handle)
|
||||||
|
.await
|
||||||
|
.ok_or_log(context);
|
||||||
|
}
|
||||||
|
future::timeout(timeout_duration, self.smtp_handle)
|
||||||
|
.await
|
||||||
|
.ok_or_log(context);
|
||||||
|
self.ephemeral_handle.cancel().await;
|
||||||
|
self.location_handle.cancel().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,19 +161,19 @@ impl ConnectivityStore {
|
|||||||
/// Set all folder states to InterruptingIdle in case they were `Connected` before.
|
/// Set all folder states to InterruptingIdle in case they were `Connected` before.
|
||||||
/// Called during `dc_maybe_network()` to make sure that `dc_accounts_all_work_done()`
|
/// Called during `dc_maybe_network()` to make sure that `dc_accounts_all_work_done()`
|
||||||
/// returns false immediately after `dc_maybe_network()`.
|
/// returns false immediately after `dc_maybe_network()`.
|
||||||
pub(crate) async fn idle_interrupted(scheduler: RwLockReadGuard<'_, Scheduler>) {
|
pub(crate) async fn idle_interrupted(scheduler: RwLockReadGuard<'_, Option<Scheduler>>) {
|
||||||
let [inbox, mvbox, sentbox] = match &*scheduler {
|
let [inbox, mvbox, sentbox] = match &*scheduler {
|
||||||
Scheduler::Running {
|
Some(Scheduler {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
..
|
..
|
||||||
} => [
|
}) => [
|
||||||
inbox.state.connectivity.clone(),
|
inbox.state.connectivity.clone(),
|
||||||
mvbox.state.connectivity.clone(),
|
mvbox.state.connectivity.clone(),
|
||||||
sentbox.state.connectivity.clone(),
|
sentbox.state.connectivity.clone(),
|
||||||
],
|
],
|
||||||
Scheduler::Stopped => return,
|
None => return,
|
||||||
};
|
};
|
||||||
drop(scheduler);
|
drop(scheduler);
|
||||||
|
|
||||||
@@ -205,20 +205,20 @@ pub(crate) async fn idle_interrupted(scheduler: RwLockReadGuard<'_, Scheduler>)
|
|||||||
/// after `maybe_network_lost()` was called.
|
/// after `maybe_network_lost()` was called.
|
||||||
pub(crate) async fn maybe_network_lost(
|
pub(crate) async fn maybe_network_lost(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
scheduler: RwLockReadGuard<'_, Scheduler>,
|
scheduler: RwLockReadGuard<'_, Option<Scheduler>>,
|
||||||
) {
|
) {
|
||||||
let stores = match &*scheduler {
|
let stores = match &*scheduler {
|
||||||
Scheduler::Running {
|
Some(Scheduler {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
..
|
..
|
||||||
} => [
|
}) => [
|
||||||
inbox.state.connectivity.clone(),
|
inbox.state.connectivity.clone(),
|
||||||
mvbox.state.connectivity.clone(),
|
mvbox.state.connectivity.clone(),
|
||||||
sentbox.state.connectivity.clone(),
|
sentbox.state.connectivity.clone(),
|
||||||
],
|
],
|
||||||
Scheduler::Stopped => return,
|
None => return,
|
||||||
};
|
};
|
||||||
drop(scheduler);
|
drop(scheduler);
|
||||||
|
|
||||||
@@ -265,16 +265,16 @@ impl Context {
|
|||||||
pub async fn get_connectivity(&self) -> Connectivity {
|
pub async fn get_connectivity(&self) -> Connectivity {
|
||||||
let lock = self.scheduler.read().await;
|
let lock = self.scheduler.read().await;
|
||||||
let stores: Vec<_> = match &*lock {
|
let stores: Vec<_> = match &*lock {
|
||||||
Scheduler::Running {
|
Some(Scheduler {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
..
|
..
|
||||||
} => [&inbox.state, &mvbox.state, &sentbox.state]
|
}) => [&inbox.state, &mvbox.state, &sentbox.state]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|state| state.connectivity.clone())
|
.map(|state| state.connectivity.clone())
|
||||||
.collect(),
|
.collect(),
|
||||||
Scheduler::Stopped => return Connectivity::NotConnected,
|
None => return Connectivity::NotConnected,
|
||||||
};
|
};
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
@@ -353,13 +353,13 @@ impl Context {
|
|||||||
|
|
||||||
let lock = self.scheduler.read().await;
|
let lock = self.scheduler.read().await;
|
||||||
let (folders_states, smtp) = match &*lock {
|
let (folders_states, smtp) = match &*lock {
|
||||||
Scheduler::Running {
|
Some(Scheduler {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
smtp,
|
smtp,
|
||||||
..
|
..
|
||||||
} => (
|
}) => (
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
Config::ConfiguredInboxFolder,
|
Config::ConfiguredInboxFolder,
|
||||||
@@ -376,7 +376,7 @@ impl Context {
|
|||||||
],
|
],
|
||||||
smtp.state.connectivity.clone(),
|
smtp.state.connectivity.clone(),
|
||||||
),
|
),
|
||||||
Scheduler::Stopped => {
|
None => {
|
||||||
return Err(anyhow!("Not started"));
|
return Err(anyhow!("Not started"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -552,17 +552,17 @@ impl Context {
|
|||||||
pub async fn all_work_done(&self) -> bool {
|
pub async fn all_work_done(&self) -> bool {
|
||||||
let lock = self.scheduler.read().await;
|
let lock = self.scheduler.read().await;
|
||||||
let stores: Vec<_> = match &*lock {
|
let stores: Vec<_> = match &*lock {
|
||||||
Scheduler::Running {
|
Some(Scheduler {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
smtp,
|
smtp,
|
||||||
..
|
..
|
||||||
} => [&inbox.state, &mvbox.state, &sentbox.state, &smtp.state]
|
}) => [&inbox.state, &mvbox.state, &sentbox.state, &smtp.state]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|state| state.connectivity.clone())
|
.map(|state| state.connectivity.clone())
|
||||||
.collect(),
|
.collect(),
|
||||||
Scheduler::Stopped => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user