feat: Context::set_config(): Restart IO scheduler if needed (#5111)

Restart the IO scheduler if needed to make the new config value effective (for `MvboxMove,
OnlyFetchMvbox, SentboxWatch` currently). Also add `set_config_internal()` which doesn't affect
running the IO scheduler. The reason is that `Scheduler::start()` itself calls `set_config()`,
although not for the mentioned keys, but still, and also Rust complains about recursive async calls.
This commit is contained in:
iequidoo
2024-02-12 14:22:23 -03:00
committed by iequidoo
parent ba35e83db2
commit b5f2c747e0
20 changed files with 180 additions and 93 deletions

View File

@@ -423,19 +423,16 @@ char* dc_get_blobdir (const dc_context_t* context);
* Sending messages to self is needed for a proper multi-account setup, * Sending messages to self is needed for a proper multi-account setup,
* however, on the other hand, may lead to unwanted notifications in non-delta clients. * however, on the other hand, may lead to unwanted notifications in non-delta clients.
* - `sentbox_watch`= 1=watch `Sent`-folder for changes, * - `sentbox_watch`= 1=watch `Sent`-folder for changes,
* 0=do not watch the `Sent`-folder (default), * 0=do not watch the `Sent`-folder (default).
* changes require restarting IO by calling dc_stop_io() and then dc_start_io().
* - `mvbox_move` = 1=detect chat messages, * - `mvbox_move` = 1=detect chat messages,
* move them to the `DeltaChat` folder, * move them to the `DeltaChat` folder,
* and watch the `DeltaChat` folder for updates (default), * and watch the `DeltaChat` folder for updates (default),
* 0=do not move chat-messages * 0=do not move chat-messages
* changes require restarting IO by calling dc_stop_io() and then dc_start_io().
* - `only_fetch_mvbox` = 1=Do not fetch messages from folders other than the * - `only_fetch_mvbox` = 1=Do not fetch messages from folders other than the
* `DeltaChat` folder. Messages will still be fetched from the * `DeltaChat` folder. Messages will still be fetched from the
* spam folder and `sendbox_watch` will also still be respected * spam folder and `sendbox_watch` will also still be respected
* if enabled. * if enabled.
* 0=watch all folders normally (default) * 0=watch all folders normally (default)
* changes require restarting IO by calling dc_stop_io() and then dc_start_io().
* - `show_emails` = DC_SHOW_EMAILS_OFF (0)= * - `show_emails` = DC_SHOW_EMAILS_OFF (0)=
* show direct replies to chats only, * show direct replies to chats only,
* DC_SHOW_EMAILS_ACCEPTED_CONTACTS (1)= * DC_SHOW_EMAILS_ACCEPTED_CONTACTS (1)=

View File

@@ -251,7 +251,7 @@ impl CommandApi {
/// Starts background tasks for a single account. /// Starts background tasks for a single account.
async fn start_io(&self, account_id: u32) -> Result<()> { async fn start_io(&self, account_id: u32) -> Result<()> {
let mut ctx = self.get_context(account_id).await?; let ctx = self.get_context(account_id).await?;
ctx.start_io().await; ctx.start_io().await;
Ok(()) Ok(())
} }
@@ -402,7 +402,7 @@ impl CommandApi {
/// Configures this account with the currently set parameters. /// Configures this account with the currently set parameters.
/// Setup the credential config before calling this. /// Setup the credential config before calling this.
async fn configure(&self, account_id: u32) -> Result<()> { async fn configure(&self, account_id: u32) -> Result<()> {
let mut ctx = self.get_context(account_id).await?; let ctx = self.get_context(account_id).await?;
ctx.stop_io().await; ctx.stop_io().await;
let result = ctx.configure().await; let result = ctx.configure().await;
if result.is_err() { if result.is_err() {
@@ -2125,13 +2125,6 @@ async fn set_config(
value, value,
) )
.await?; .await?;
match key {
"sentbox_watch" | "mvbox_move" | "only_fetch_mvbox" => {
ctx.restart_io_if_running().await;
}
_ => {}
}
} }
Ok(()) Ok(())
} }

View File

@@ -401,7 +401,7 @@ enum ExitResult {
async fn handle_cmd( async fn handle_cmd(
line: &str, line: &str,
mut ctx: Context, ctx: Context,
selected_chat: &mut ChatId, selected_chat: &mut ChatId,
) -> Result<ExitResult, Error> { ) -> Result<ExitResult, Error> {
let mut args = line.splitn(2, ' '); let mut args = line.splitn(2, ' ');

View File

@@ -382,6 +382,21 @@ def test_webxdc_download_on_demand(acfactory, data, lp):
assert msgs_changed_event.data2 == 0 assert msgs_changed_event.data2 == 0
def test_enable_mvbox_move(acfactory, lp):
(ac1,) = acfactory.get_online_accounts(1)
lp.sec("ac2: start without mvbox thread")
ac2 = acfactory.new_online_configuring_account(mvbox_move=False)
acfactory.bring_accounts_online()
lp.sec("ac2: configuring mvbox")
ac2.set_config("mvbox_move", "1")
lp.sec("ac1: send message and wait for ac2 to receive it")
acfactory.get_accepted_chat(ac1, ac2).send_text("message1")
assert ac2._evtracker.wait_next_incoming_message().text == "message1"
def test_mvbox_sentbox_threads(acfactory, lp): def test_mvbox_sentbox_threads(acfactory, lp):
lp.sec("ac1: start with mvbox thread") lp.sec("ac1: start with mvbox thread")
ac1 = acfactory.new_online_configuring_account(mvbox_move=True, sentbox_watch=True) ac1 = acfactory.new_online_configuring_account(mvbox_move=True, sentbox_watch=True)

View File

@@ -216,7 +216,7 @@ async fn update_authservid_candidates(
if old_ids != new_ids { if old_ids != new_ids {
let new_config = new_ids.into_iter().collect::<Vec<_>>().join(" "); let new_config = new_ids.into_iter().collect::<Vec<_>>().join(" ");
context context
.set_config(Config::AuthservIdCandidates, Some(&new_config)) .set_config_internal(Config::AuthservIdCandidates, Some(&new_config))
.await?; .await?;
// Updating the authservid candidates may mean that we now consider // Updating the authservid candidates may mean that we now consider
// emails as "failed" which "passed" previously, so we need to // emails as "failed" which "passed" previously, so we need to

View File

@@ -783,7 +783,9 @@ impl ChatId {
context.emit_msgs_changed_without_ids(); context.emit_msgs_changed_without_ids();
context.set_config(Config::LastHousekeeping, None).await?; context
.set_config_internal(Config::LastHousekeeping, None)
.await?;
context.scheduler.interrupt_inbox().await; context.scheduler.interrupt_inbox().await;
if chat.is_self_talk() { if chat.is_self_talk() {
@@ -4266,7 +4268,9 @@ pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Resul
(), (),
) )
.await?; .await?;
context.set_config(Config::QuotaExceeding, None).await?; context
.set_config_internal(Config::QuotaExceeding, None)
.await?;
Ok(()) Ok(())
} }

View File

@@ -367,11 +367,23 @@ impl Config {
/// multiple users are sharing an account. Another example is `Self::SyncMsgs` itself which /// multiple users are sharing an account. Another example is `Self::SyncMsgs` itself which
/// mustn't be controlled by other devices. /// mustn't be controlled by other devices.
pub(crate) fn is_synced(&self) -> bool { pub(crate) fn is_synced(&self) -> bool {
// We don't restart IO from the synchronisation code, so this is to be on the safe side.
if self.needs_io_restart() {
return false;
}
matches!( matches!(
self, self,
Self::Displayname | Self::MdnsEnabled | Self::ShowEmails Self::Displayname | Self::MdnsEnabled | Self::ShowEmails
) )
} }
/// Whether the config option needs an IO scheduler restart to take effect.
pub(crate) fn needs_io_restart(&self) -> bool {
matches!(
self,
Config::MvboxMove | Config::OnlyFetchMvbox | Config::SentboxWatch
)
}
} }
impl Context { impl Context {
@@ -491,10 +503,50 @@ impl Context {
} }
} }
/// Set the given config key. fn check_config(key: Config, value: Option<&str>) -> Result<()> {
/// If `None` is passed as a value the value is cleared and set to the default if there is one. match key {
Config::Socks5Enabled
| Config::BccSelf
| Config::E2eeEnabled
| Config::MdnsEnabled
| Config::SentboxWatch
| Config::MvboxMove
| Config::OnlyFetchMvbox
| Config::FetchExistingMsgs
| Config::DeleteToTrash
| Config::SaveMimeHeaders
| Config::Configured
| Config::Bot
| Config::NotifyAboutWrongPw
| Config::SyncMsgs
| Config::SignUnencrypted
| Config::DisableIdle => {
ensure!(
matches!(value, None | Some("0") | Some("1")),
"Boolean value must be either 0 or 1"
);
}
_ => (),
}
Ok(())
}
/// Set the given config key and make it effective.
/// This may restart the IO scheduler. If `None` is passed as a value the value is cleared and
/// set to the default if there is one.
pub async fn set_config(&self, key: Config, value: Option<&str>) -> Result<()> { pub async fn set_config(&self, key: Config, value: Option<&str>) -> Result<()> {
self.set_config_ex(key.is_synced().into(), key, value).await Self::check_config(key, value)?;
let _pause = match key.needs_io_restart() {
true => self.scheduler.pause(self.clone()).await?,
_ => Default::default(),
};
self.set_config_internal(key, value).await?;
Ok(())
}
pub(crate) async fn set_config_internal(&self, key: Config, value: Option<&str>) -> Result<()> {
self.set_config_ex(Sync, key, value).await
} }
pub(crate) async fn set_config_ex( pub(crate) async fn set_config_ex(
@@ -503,7 +555,10 @@ impl Context {
key: Config, key: Config,
mut value: Option<&str>, mut value: Option<&str>,
) -> Result<()> { ) -> Result<()> {
Self::check_config(key, value)?;
let sync = sync == Sync && key.is_synced();
let better_value; let better_value;
match key { match key {
Config::Selfavatar => { Config::Selfavatar => {
self.sql self.sql
@@ -536,28 +591,6 @@ impl Context {
} }
self.sql.set_raw_config(key.as_ref(), value).await?; self.sql.set_raw_config(key.as_ref(), value).await?;
} }
Config::Socks5Enabled
| Config::BccSelf
| Config::E2eeEnabled
| Config::MdnsEnabled
| Config::SentboxWatch
| Config::MvboxMove
| Config::OnlyFetchMvbox
| Config::FetchExistingMsgs
| Config::DeleteToTrash
| Config::SaveMimeHeaders
| Config::Configured
| Config::Bot
| Config::NotifyAboutWrongPw
| Config::SyncMsgs
| Config::SignUnencrypted
| Config::DisableIdle => {
ensure!(
matches!(value, None | Some("0") | Some("1")),
"Boolean value must be either 0 or 1"
);
self.sql.set_raw_config(key.as_ref(), value).await?;
}
Config::Addr => { Config::Addr => {
self.sql self.sql
.set_raw_config(key.as_ref(), value.map(|s| s.to_lowercase()).as_deref()) .set_raw_config(key.as_ref(), value.map(|s| s.to_lowercase()).as_deref())
@@ -570,7 +603,7 @@ impl Context {
if key.is_synced() { if key.is_synced() {
self.emit_event(EventType::ConfigSynced { key }); self.emit_event(EventType::ConfigSynced { key });
} }
if sync != Sync { if !sync {
return Ok(()); return Ok(());
} }
let Some(val) = value else { let Some(val) = value else {
@@ -597,8 +630,7 @@ impl Context {
/// Set the given config to a boolean value. /// Set the given config to a boolean value.
pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> { pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> {
self.set_config(key, if value { Some("1") } else { Some("0") }) self.set_config(key, from_bool(value)).await?;
.await?;
Ok(()) Ok(())
} }
@@ -618,6 +650,11 @@ impl Context {
} }
} }
/// Returns a value for use in `Context::set_config_*()` for the given `bool`.
pub(crate) fn from_bool(val: bool) -> Option<&'static str> {
Some(if val { "1" } else { "0" })
}
// Separate impl block for self address handling // Separate impl block for self address handling
impl Context { impl Context {
/// Determine whether the specified addr maps to the/a self addr. /// Determine whether the specified addr maps to the/a self addr.
@@ -644,13 +681,13 @@ impl Context {
let mut secondary_addrs = self.get_all_self_addrs().await?; let mut secondary_addrs = self.get_all_self_addrs().await?;
// never store a primary address also as a secondary // never store a primary address also as a secondary
secondary_addrs.retain(|a| !addr_cmp(a, primary_new)); secondary_addrs.retain(|a| !addr_cmp(a, primary_new));
self.set_config( self.set_config_internal(
Config::SecondaryAddrs, Config::SecondaryAddrs,
Some(secondary_addrs.join(" ").as_str()), Some(secondary_addrs.join(" ").as_str()),
) )
.await?; .await?;
self.set_config(Config::ConfiguredAddr, Some(primary_new)) self.set_config_internal(Config::ConfiguredAddr, Some(primary_new))
.await?; .await?;
Ok(()) Ok(())

View File

@@ -22,7 +22,7 @@ use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use server_params::{expand_param_vector, ServerParams}; use server_params::{expand_param_vector, ServerParams};
use tokio::task; use tokio::task;
use crate::config::Config; use crate::config::{self, Config};
use crate::contact::addr_cmp; use crate::contact::addr_cmp;
use crate::context::Context; use crate::context::Context;
use crate::imap::Imap; use crate::imap::Imap;
@@ -112,12 +112,13 @@ impl Context {
let mut param = LoginParam::load_candidate_params(self).await?; let mut param = LoginParam::load_candidate_params(self).await?;
let old_addr = self.get_config(Config::ConfiguredAddr).await?; let old_addr = self.get_config(Config::ConfiguredAddr).await?;
let success = configure(self, &mut param).await; let success = configure(self, &mut param).await;
self.set_config(Config::NotifyAboutWrongPw, None).await?; self.set_config_internal(Config::NotifyAboutWrongPw, None)
.await?;
on_configure_completed(self, param, old_addr).await?; on_configure_completed(self, param, old_addr).await?;
success?; success?;
self.set_config(Config::NotifyAboutWrongPw, Some("1")) self.set_config_internal(Config::NotifyAboutWrongPw, Some("1"))
.await?; .await?;
Ok(()) Ok(())
} }
@@ -473,7 +474,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
// the trailing underscore is correct // the trailing underscore is correct
param.save_as_configured_params(ctx).await?; param.save_as_configured_params(ctx).await?;
ctx.set_config(Config::ConfiguredTimestamp, Some(&time().to_string())) ctx.set_config_internal(Config::ConfiguredTimestamp, Some(&time().to_string()))
.await?; .await?;
progress!(ctx, 920); progress!(ctx, 920);
@@ -481,7 +482,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
e2ee::ensure_secret_key_exists(ctx).await?; e2ee::ensure_secret_key_exists(ctx).await?;
info!(ctx, "key generation completed"); info!(ctx, "key generation completed");
ctx.set_config_bool(Config::FetchedExistingMsgs, false) ctx.set_config_internal(Config::FetchedExistingMsgs, config::from_bool(false))
.await?; .await?;
ctx.scheduler.interrupt_inbox().await; ctx.scheduler.interrupt_inbox().await;

View File

@@ -1550,7 +1550,7 @@ pub(crate) async fn set_profile_image(
if contact_id == ContactId::SELF { if contact_id == ContactId::SELF {
if was_encrypted { if was_encrypted {
context context
.set_config(Config::Selfavatar, Some(profile_image)) .set_config_internal(Config::Selfavatar, Some(profile_image))
.await?; .await?;
} else { } else {
info!(context, "Do not use unencrypted selfavatar."); info!(context, "Do not use unencrypted selfavatar.");
@@ -1563,7 +1563,9 @@ pub(crate) async fn set_profile_image(
AvatarAction::Delete => { AvatarAction::Delete => {
if contact_id == ContactId::SELF { if contact_id == ContactId::SELF {
if was_encrypted { if was_encrypted {
context.set_config(Config::Selfavatar, None).await?; context
.set_config_internal(Config::Selfavatar, None)
.await?;
} else { } else {
info!(context, "Do not use unencrypted selfavatar deletion."); info!(context, "Do not use unencrypted selfavatar deletion.");
} }
@@ -1595,7 +1597,7 @@ pub(crate) async fn set_status(
if contact_id == ContactId::SELF { if contact_id == ContactId::SELF {
if encrypted && has_chat_version { if encrypted && has_chat_version {
context context
.set_config(Config::Selfstatus, Some(&status)) .set_config_internal(Config::Selfstatus, Some(&status))
.await?; .await?;
} }
} else { } else {

View File

@@ -408,7 +408,7 @@ impl Context {
} }
/// Starts the IO scheduler. /// Starts the IO scheduler.
pub async fn start_io(&mut self) { pub async fn start_io(&self) {
if !self.is_configured().await.unwrap_or_default() { if !self.is_configured().await.unwrap_or_default() {
warn!(self, "can not start io on a context that is not configured"); warn!(self, "can not start io on a context that is not configured");
return; return;

View File

@@ -451,7 +451,10 @@ impl Imap {
&& err.to_string().to_lowercase().contains("authentication") && err.to_string().to_lowercase().contains("authentication")
&& context.get_config_bool(Config::NotifyAboutWrongPw).await? && context.get_config_bool(Config::NotifyAboutWrongPw).await?
{ {
if let Err(e) = context.set_config(Config::NotifyAboutWrongPw, None).await { if let Err(e) = context
.set_config_internal(Config::NotifyAboutWrongPw, None)
.await
{
warn!(context, "{:#}", e); warn!(context, "{:#}", e);
} }
drop(lock); drop(lock);
@@ -1877,16 +1880,16 @@ impl Imap {
.context("failed to configure mvbox")?; .context("failed to configure mvbox")?;
context context
.set_config(Config::ConfiguredInboxFolder, Some("INBOX")) .set_config_internal(Config::ConfiguredInboxFolder, Some("INBOX"))
.await?; .await?;
if let Some(mvbox_folder) = mvbox_folder { if let Some(mvbox_folder) = mvbox_folder {
info!(context, "Setting MVBOX FOLDER TO {}", &mvbox_folder); info!(context, "Setting MVBOX FOLDER TO {}", &mvbox_folder);
context context
.set_config(Config::ConfiguredMvboxFolder, Some(mvbox_folder)) .set_config_internal(Config::ConfiguredMvboxFolder, Some(mvbox_folder))
.await?; .await?;
} }
for (config, name) in folder_configs { for (config, name) in folder_configs {
context.set_config(config, Some(&name)).await?; context.set_config_internal(config, Some(&name)).await?;
} }
context context
.sql .sql

View File

@@ -89,7 +89,7 @@ impl Imap {
Config::ConfiguredTrashFolder, Config::ConfiguredTrashFolder,
] { ] {
context context
.set_config(conf, folder_configs.get(&conf).map(|s| s.as_str())) .set_config_internal(conf, folder_configs.get(&conf).map(|s| s.as_str()))
.await?; .await?;
} }

View File

@@ -1522,7 +1522,9 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
if !msg_ids.is_empty() { if !msg_ids.is_empty() {
// Run housekeeping to delete unused blobs. // Run housekeeping to delete unused blobs.
context.set_config(Config::LastHousekeeping, None).await?; context
.set_config_internal(Config::LastHousekeeping, None)
.await?;
} }
// Interrupt Inbox loop to start message deletion and run housekeeping. // Interrupt Inbox loop to start message deletion and run housekeeping.
@@ -1550,7 +1552,7 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()>
let old_last_msg_id = MsgId::new(context.get_config_u32(Config::LastMsgId).await?); let old_last_msg_id = MsgId::new(context.get_config_u32(Config::LastMsgId).await?);
let last_msg_id = msg_ids.iter().fold(&old_last_msg_id, std::cmp::max); let last_msg_id = msg_ids.iter().fold(&old_last_msg_id, std::cmp::max);
context context
.set_config_u32(Config::LastMsgId, last_msg_id.to_u32()) .set_config_internal(Config::LastMsgId, Some(&last_msg_id.to_u32().to_string()))
.await?; .await?;
let msgs = context let msgs = context

View File

@@ -560,8 +560,12 @@ async fn set_account_from_qr(context: &Context, qr: &str) -> Result<()> {
"Cannot create account, response from {url_str:?} is malformed:\n{response_text:?}" "Cannot create account, response from {url_str:?} is malformed:\n{response_text:?}"
) )
})?; })?;
context.set_config(Config::Addr, Some(&email)).await?; context
context.set_config(Config::MailPw, Some(&password)).await?; .set_config_internal(Config::Addr, Some(&email))
.await?;
context
.set_config_internal(Config::MailPw, Some(&password))
.await?;
Ok(()) Ok(())
} else { } else {
@@ -589,7 +593,7 @@ pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> {
instance_pattern, instance_pattern,
} => { } => {
context context
.set_config(Config::WebrtcInstance, Some(&instance_pattern)) .set_config_internal(Config::WebrtcInstance, Some(&instance_pattern))
.await?; .await?;
} }
Qr::WithdrawVerifyContact { Qr::WithdrawVerifyContact {

View File

@@ -163,7 +163,9 @@ pub(crate) async fn configure_from_login_qr(
address: &str, address: &str,
options: LoginOptions, options: LoginOptions,
) -> Result<()> { ) -> Result<()> {
context.set_config(Config::Addr, Some(address)).await?; context
.set_config_internal(Config::Addr, Some(address))
.await?;
match options { match options {
LoginOptions::V1 { LoginOptions::V1 {
@@ -181,27 +183,35 @@ pub(crate) async fn configure_from_login_qr(
smtp_security, smtp_security,
smtp_certificate_checks, smtp_certificate_checks,
} => { } => {
context.set_config(Config::MailPw, Some(&mail_pw)).await?; context
.set_config_internal(Config::MailPw, Some(&mail_pw))
.await?;
if let Some(value) = imap_host { if let Some(value) = imap_host {
context.set_config(Config::MailServer, Some(&value)).await?; context
.set_config_internal(Config::MailServer, Some(&value))
.await?;
} }
if let Some(value) = imap_port { if let Some(value) = imap_port {
context context
.set_config(Config::MailPort, Some(&value.to_string())) .set_config_internal(Config::MailPort, Some(&value.to_string()))
.await?; .await?;
} }
if let Some(value) = imap_username { if let Some(value) = imap_username {
context.set_config(Config::MailUser, Some(&value)).await?; context
.set_config_internal(Config::MailUser, Some(&value))
.await?;
} }
if let Some(value) = imap_password { if let Some(value) = imap_password {
context.set_config(Config::MailPw, Some(&value)).await?; context
.set_config_internal(Config::MailPw, Some(&value))
.await?;
} }
if let Some(value) = imap_security { if let Some(value) = imap_security {
let code = value let code = value
.to_u8() .to_u8()
.context("could not convert imap security value to number")?; .context("could not convert imap security value to number")?;
context context
.set_config(Config::MailSecurity, Some(&code.to_string())) .set_config_internal(Config::MailSecurity, Some(&code.to_string()))
.await?; .await?;
} }
if let Some(value) = imap_certificate_checks { if let Some(value) = imap_certificate_checks {
@@ -209,29 +219,35 @@ pub(crate) async fn configure_from_login_qr(
.to_u32() .to_u32()
.context("could not convert imap certificate checks value to number")?; .context("could not convert imap certificate checks value to number")?;
context context
.set_config(Config::ImapCertificateChecks, Some(&code.to_string())) .set_config_internal(Config::ImapCertificateChecks, Some(&code.to_string()))
.await?; .await?;
} }
if let Some(value) = smtp_host { if let Some(value) = smtp_host {
context.set_config(Config::SendServer, Some(&value)).await?; context
.set_config_internal(Config::SendServer, Some(&value))
.await?;
} }
if let Some(value) = smtp_port { if let Some(value) = smtp_port {
context context
.set_config(Config::SendPort, Some(&value.to_string())) .set_config_internal(Config::SendPort, Some(&value.to_string()))
.await?; .await?;
} }
if let Some(value) = smtp_username { if let Some(value) = smtp_username {
context.set_config(Config::SendUser, Some(&value)).await?; context
.set_config_internal(Config::SendUser, Some(&value))
.await?;
} }
if let Some(value) = smtp_password { if let Some(value) = smtp_password {
context.set_config(Config::SendPw, Some(&value)).await?; context
.set_config_internal(Config::SendPw, Some(&value))
.await?;
} }
if let Some(value) = smtp_security { if let Some(value) = smtp_security {
let code = value let code = value
.to_u8() .to_u8()
.context("could not convert smtp security value to number")?; .context("could not convert smtp security value to number")?;
context context
.set_config(Config::SendSecurity, Some(&code.to_string())) .set_config_internal(Config::SendSecurity, Some(&code.to_string()))
.await?; .await?;
} }
if let Some(value) = smtp_certificate_checks { if let Some(value) = smtp_certificate_checks {
@@ -239,7 +255,7 @@ pub(crate) async fn configure_from_login_qr(
.to_u32() .to_u32()
.context("could not convert smtp certificate checks value to number")?; .context("could not convert smtp certificate checks value to number")?;
context context
.set_config(Config::SmtpCertificateChecks, Some(&code.to_string())) .set_config_internal(Config::SmtpCertificateChecks, Some(&code.to_string()))
.await?; .await?;
} }
Ok(()) Ok(())

View File

@@ -132,13 +132,17 @@ impl Context {
highest, highest,
self.get_config_int(Config::QuotaExceeding).await? as u64, self.get_config_int(Config::QuotaExceeding).await? as u64,
) { ) {
self.set_config(Config::QuotaExceeding, Some(&highest.to_string())) self.set_config_internal(
.await?; Config::QuotaExceeding,
Some(&highest.to_string()),
)
.await?;
let mut msg = Message::new(Viewtype::Text); let mut msg = Message::new(Viewtype::Text);
msg.text = stock_str::quota_exceeding(self, highest).await; msg.text = stock_str::quota_exceeding(self, highest).await;
add_device_msg_with_importance(self, None, Some(&mut msg), true).await?; add_device_msg_with_importance(self, None, Some(&mut msg), true).await?;
} else if highest <= QUOTA_ALLCLEAR_PERCENTAGE { } else if highest <= QUOTA_ALLCLEAR_PERCENTAGE {
self.set_config(Config::QuotaExceeding, None).await?; self.set_config_internal(Config::QuotaExceeding, None)
.await?;
} }
} }
Err(err) => warn!(self, "cannot get highest quota usage: {:#}", err), Err(err) => warn!(self, "cannot get highest quota usage: {:#}", err),

View File

@@ -1034,7 +1034,10 @@ async fn add_parts(
}; };
if update_config { if update_config {
context context
.set_config(Config::LastCantDecryptOutgoingMsgs, Some(&now.to_string())) .set_config_internal(
Config::LastCantDecryptOutgoingMsgs,
Some(&now.to_string()),
)
.await?; .await?;
} }
} }

View File

@@ -12,7 +12,7 @@ use tokio::sync::{oneshot, RwLock, RwLockWriteGuard};
use tokio::task; use tokio::task;
use self::connectivity::ConnectivityStore; use self::connectivity::ConnectivityStore;
use crate::config::Config; use crate::config::{self, Config};
use crate::contact::{ContactId, RecentlySeenLoop}; use crate::contact::{ContactId, RecentlySeenLoop};
use crate::context::Context; use crate::context::Context;
use crate::download::{download_msg, DownloadState}; use crate::download::{download_msg, DownloadState};
@@ -290,7 +290,7 @@ enum InnerSchedulerState {
/// ///
/// Returned by [`SchedulerState::pause`]. To resume the IO scheduler simply drop this /// Returned by [`SchedulerState::pause`]. To resume the IO scheduler simply drop this
/// guard. /// guard.
#[derive(Debug)] #[derive(Default, Debug)]
pub(crate) struct IoPausedGuard { pub(crate) struct IoPausedGuard {
sender: Option<oneshot::Sender<()>>, sender: Option<oneshot::Sender<()>>,
} }
@@ -439,8 +439,12 @@ async fn inbox_loop(
// //
// This operation is not critical enough to retry, // This operation is not critical enough to retry,
// especially if the error is persistent. // especially if the error is persistent.
if let Err(err) = if let Err(err) = ctx
ctx.set_config_bool(Config::FetchedExistingMsgs, true).await .set_config_internal(
Config::FetchedExistingMsgs,
config::from_bool(true),
)
.await
{ {
warn!(ctx, "Can't set Config::FetchedExistingMsgs: {:#}", err); warn!(ctx, "Can't set Config::FetchedExistingMsgs: {:#}", err);
} }

View File

@@ -248,7 +248,7 @@ impl Sql {
msg.set_text(stock_str::delete_server_turned_off(context).await); msg.set_text(stock_str::delete_server_turned_off(context).await);
add_device_msg(context, None, Some(&mut msg)).await?; add_device_msg(context, None, Some(&mut msg)).await?;
context context
.set_config(Config::DeleteServerAfter, Some("0")) .set_config_internal(Config::DeleteServerAfter, Some("0"))
.await?; .await?;
} }
} }
@@ -259,12 +259,14 @@ impl Sql {
match blob.recode_to_avatar_size(context).await { match blob.recode_to_avatar_size(context).await {
Ok(()) => { Ok(()) => {
context context
.set_config(Config::Selfavatar, Some(&avatar)) .set_config_internal(Config::Selfavatar, Some(&avatar))
.await? .await?
} }
Err(e) => { Err(e) => {
warn!(context, "Migrations can't recode avatar, removing. {:#}", e); warn!(context, "Migrations can't recode avatar, removing. {:#}", e);
context.set_config(Config::Selfavatar, None).await? context
.set_config_internal(Config::Selfavatar, None)
.await?
} }
} }
} }
@@ -702,7 +704,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> {
// Setting `Config::LastHousekeeping` at the beginning avoids endless loops when things do not // Setting `Config::LastHousekeeping` at the beginning avoids endless loops when things do not
// work out for whatever reason or are interrupted by the OS. // work out for whatever reason or are interrupted by the OS.
if let Err(e) = context if let Err(e) = context
.set_config(Config::LastHousekeeping, Some(&time().to_string())) .set_config_internal(Config::LastHousekeeping, Some(&time().to_string()))
.await .await
{ {
warn!(context, "Can't set config: {e:#}."); warn!(context, "Can't set config: {e:#}.");

View File

@@ -368,7 +368,7 @@ UPDATE chats SET protected=1, type=120 WHERE type=130;"#,
if let Ok(addr) = context.get_primary_self_addr().await { if let Ok(addr) = context.get_primary_self_addr().await {
if let Ok(domain) = EmailAddress::new(&addr).map(|email| email.domain) { if let Ok(domain) = EmailAddress::new(&addr).map(|email| email.domain) {
context context
.set_config( .set_config_internal(
Config::ConfiguredProvider, Config::ConfiguredProvider,
get_provider_by_domain(&domain).map(|provider| provider.id), get_provider_by_domain(&domain).map(|provider| provider.id),
) )