diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index fc68046d8..5abdd3aec 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1570,6 +1570,8 @@ pub unsafe extern "C" fn dc_delete_msgs( let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt); block_on(message::delete_msgs(ctx, &msg_ids)) + .log_err(ctx, "failed dc_delete_msgs() call") + .ok(); } #[no_mangle] @@ -2047,7 +2049,9 @@ pub unsafe extern "C" fn dc_send_locations_to_chat( ctx, ChatId::new(chat_id), seconds as i64, - )); + )) + .log_err(ctx, "Failed dc_send_locations_to_chat()") + .ok(); } #[no_mangle] @@ -2066,7 +2070,8 @@ pub unsafe extern "C" fn dc_is_sending_locations_to_chat( Some(ChatId::new(chat_id)) }; - block_on(location::is_sending_locations_to_chat(ctx, chat_id)) as libc::c_int + block_on(location::is_sending_locations_to_chat(ctx, chat_id)) + .unwrap_or_log_default(ctx, "Failed dc_is_sending_locations_to_chat()") as libc::c_int } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index ef8ece2d8..bec5937c5 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -602,7 +602,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu ); } } - if location::is_sending_locations_to_chat(&context, None).await { + if location::is_sending_locations_to_chat(&context, None).await? { println!("Location streaming enabled."); } println!("{} chats", cnt); @@ -773,7 +773,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu &context, Some(sel_chat.as_ref().unwrap().get_id()) ) - .await, + .await?, ); } "getlocations" => { @@ -818,7 +818,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu sel_chat.as_ref().unwrap().get_id(), seconds, ) - .await; + .await?; println!( "Locations will be sent to Chat#{} for {} seconds. Use 'setlocation ' to play around.", sel_chat.as_ref().unwrap().get_id(), @@ -1067,7 +1067,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu ensure!(!arg1.is_empty(), "Argument missing."); let mut ids = [MsgId::new(0); 1]; ids[0] = MsgId::new(arg1.parse()?); - message::delete_msgs(&context, &ids).await; + message::delete_msgs(&context, &ids).await?; } "listcontacts" | "contacts" | "listverified" => { let contacts = Contact::get_all( diff --git a/src/chat.rs b/src/chat.rs index 2befb612b..cd0dfd12c 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -183,7 +183,7 @@ impl ChatId { || contact_id == DC_CONTACT_ID_SELF { let chat_id = ChatId::get_for_contact(context, contact_id).await?; - Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat).await; + Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat).await?; chat_id } else { warn!( @@ -284,7 +284,7 @@ impl ChatId { for contact_id in get_chat_contacts(context, self).await? { if contact_id != DC_CONTACT_ID_SELF { Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat) - .await; + .await?; } } } @@ -497,7 +497,7 @@ impl ChatId { chat_id: ChatId::new(0), }); - job::kill_action(context, Action::Housekeeping).await; + job::kill_action(context, Action::Housekeeping).await?; let j = job::Job::new(Action::Housekeeping, 0, Params::new(), 10); job::add(context, j).await; @@ -2450,19 +2450,15 @@ impl rusqlite::types::FromSql for MuteDuration { pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuration) -> Result<()> { ensure!(!chat_id.is_special(), "Invalid chat ID"); - if context + context .sql .execute( "UPDATE chats SET muted_until=? WHERE id=?;", paramsv![duration, chat_id], ) .await - .is_ok() - { - context.emit_event(EventType::ChatModified(chat_id)); - } else { - bail!("Failed to set mute duration, chat might not exist -"); - } + .context(format!("Failed to set mute duration for {}", chat_id))?; + context.emit_event(EventType::ChatModified(chat_id)); Ok(()) } @@ -3252,7 +3248,9 @@ mod tests { assert!(chat.get_profile_image(&t).await.unwrap().is_some()); // delete device message, make sure it is not added again - message::delete_msgs(&t, &[*msg1_id.as_ref().unwrap()]).await; + message::delete_msgs(&t, &[*msg1_id.as_ref().unwrap()]) + .await + .unwrap(); let msg1 = message::Message::load_from_db(&t, *msg1_id.as_ref().unwrap()).await; assert!(msg1.is_err() || msg1.unwrap().chat_id.is_trash()); let msg3_id = add_device_msg(&t, Some("any-label"), Some(&mut msg2)).await; diff --git a/src/config.rs b/src/config.rs index f5654e678..eeb2ade69 100644 --- a/src/config.rs +++ b/src/config.rs @@ -317,7 +317,7 @@ impl Context { .set_raw_config(key, value) .await .map_err(Into::into); - job::schedule_resync(self).await; + job::schedule_resync(self).await?; ret } _ => { diff --git a/src/contact.rs b/src/contact.rs index f071eb99c..80e500867 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -1109,15 +1109,19 @@ impl Contact { .unwrap_or_default() } - pub async fn scaleup_origin_by_id(context: &Context, contact_id: u32, origin: Origin) -> bool { + pub async fn scaleup_origin_by_id( + context: &Context, + contact_id: u32, + origin: Origin, + ) -> Result<()> { context .sql .execute( "UPDATE contacts SET origin=? WHERE id=? AND origin bool { +pub async fn kill_action(context: &Context, action: Action) -> Result<()> { context .sql .execute("DELETE FROM jobs WHERE action=?;", paramsv![action]) - .await - .is_ok() + .await?; + Ok(()) } /// Remove jobs with specified IDs. @@ -1183,13 +1182,14 @@ async fn send_mdn(context: &Context, msg: &Message) -> Result<()> { Ok(()) } -pub(crate) async fn schedule_resync(context: &Context) { - kill_action(context, Action::ResyncFolders).await; +pub(crate) async fn schedule_resync(context: &Context) -> Result<()> { + kill_action(context, Action::ResyncFolders).await?; add( context, Job::new(Action::ResyncFolders, 0, Params::new(), 0), ) .await; + Ok(()) } /// Creates a job. @@ -1238,21 +1238,15 @@ pub async fn add(context: &Context, job: Job) { } } -async fn load_housekeeping_job(context: &Context) -> Option { - let last_time = match context.get_config_i64(Config::LastHousekeeping).await { - Ok(last_time) => last_time, - Err(err) => { - warn!(context, "failed to load housekeeping config: {:?}", err); - return None; - } - }; +async fn load_housekeeping_job(context: &Context) -> Result> { + let last_time = context.get_config_i64(Config::LastHousekeeping).await?; let next_time = last_time + (60 * 60 * 24); if next_time <= time() { - kill_action(context, Action::Housekeeping).await; - Some(Job::new(Action::Housekeeping, 0, Params::new(), 0)) + kill_action(context, Action::Housekeeping).await?; + Ok(Some(Job::new(Action::Housekeeping, 0, Params::new(), 0))) } else { - None + Ok(None) } } @@ -1266,20 +1260,9 @@ pub(crate) async fn load_next( context: &Context, thread: Thread, info: &InterruptInfo, -) -> Option { +) -> Result> { info!(context, "loading job for {}-thread", thread); - while !context.sql.is_open().await { - // The db is closed, which means that this thread should not be running. - // Wait until the db is re-opened (if we returned None, this thread might do further damage) - warn!( - context, - "{}: load_next() was called but the db was not opened, THIS SHOULD NOT HAPPEN. Waiting...", - thread - ); - sleep(Duration::from_millis(500)).await; - } - let query; let params; let t = time(); @@ -1346,51 +1329,38 @@ LIMIT 1; info!(context, "cleaning up job, because of {}", err); // TODO: improve by only doing a single query - match context + let id = context .sql .query_row(query, params.clone(), |row| row.get::<_, i32>(0)) .await - { - Ok(id) => { - if let Err(err) = context - .sql - .execute("DELETE FROM jobs WHERE id=?;", paramsv![id]) - .await - { - warn!(context, "failed to delete job {}: {:?}", id, err); - } - } - Err(err) => { - error!(context, "failed to retrieve invalid job from DB: {}", err); - break None; - } - } + .context("Failed to retrieve invalid job ID from the database")?; + context + .sql + .execute("DELETE FROM jobs WHERE id=?;", paramsv![id]) + .await + .with_context(|| format!("Failed to delete invalid job {}", id))?; } } }; match thread { Thread::Unknown => { - error!(context, "unknown thread for job"); - None + bail!("unknown thread for job") } Thread::Imap => { if let Some(job) = job { if job.action < Action::DeleteMsgOnImap { - load_imap_deletion_job(context) - .await - .unwrap_or_default() - .or(Some(job)) + Ok(load_imap_deletion_job(context).await?.or(Some(job))) } else { - Some(job) + Ok(Some(job)) } - } else if let Some(job) = load_imap_deletion_job(context).await.unwrap_or_default() { - Some(job) + } else if let Some(job) = load_imap_deletion_job(context).await? { + Ok(Some(job)) } else { - load_housekeeping_job(context).await + Ok(load_housekeeping_job(context).await?) } } - Thread::Smtp => job, + Thread::Smtp => Ok(job), } } @@ -1422,7 +1392,7 @@ mod tests { } #[async_std::test] - async fn test_load_next_job_two() { + async fn test_load_next_job_two() -> Result<()> { // We want to ensure that loading jobs skips over jobs which // fails to load from the database instead of failing to load // all jobs. @@ -1433,7 +1403,7 @@ mod tests { Thread::from(Action::MoveMsg), &InterruptInfo::new(false, None), ) - .await; + .await?; // The housekeeping job should be loaded as we didn't run housekeeping in the last day: assert_eq!(jobs.unwrap().action, Action::Housekeeping); @@ -1443,12 +1413,13 @@ mod tests { Thread::from(Action::MoveMsg), &InterruptInfo::new(false, None), ) - .await; + .await?; assert!(jobs.is_some()); + Ok(()) } #[async_std::test] - async fn test_load_next_job_one() { + async fn test_load_next_job_one() -> Result<()> { let t = TestContext::new().await; insert_job(&t, 1, true).await; @@ -1458,7 +1429,8 @@ mod tests { Thread::from(Action::MoveMsg), &InterruptInfo::new(false, None), ) - .await; + .await?; assert!(jobs.is_some()); + Ok(()) } } diff --git a/src/location.rs b/src/location.rs index b35c5d078..3f739d6d5 100644 --- a/src/location.rs +++ b/src/location.rs @@ -1,7 +1,7 @@ //! Location handling. use std::convert::TryFrom; -use anyhow::{ensure, Error}; +use anyhow::{ensure, Result}; use bitflags::bitflags; use quick_xml::events::{BytesEnd, BytesStart, BytesText}; @@ -63,7 +63,7 @@ impl Kml { Default::default() } - pub fn parse(context: &Context, to_parse: &[u8]) -> Result { + pub fn parse(context: &Context, to_parse: &[u8]) -> Result { ensure!(to_parse.len() <= 1024 * 1024, "kml-file is too large"); let mut reader = quick_xml::Reader::from_reader(to_parse); @@ -191,54 +191,55 @@ impl Kml { } /// Enables location streaming in chat identified by `chat_id` for `seconds` seconds. -pub async fn send_locations_to_chat(context: &Context, chat_id: ChatId, seconds: i64) { +pub async fn send_locations_to_chat( + context: &Context, + chat_id: ChatId, + seconds: i64, +) -> Result<()> { + ensure!(seconds >= 0); + ensure!(!chat_id.is_special()); let now = time(); - if !(seconds < 0 || chat_id.is_special()) { - let is_sending_locations_before = - is_sending_locations_to_chat(context, Some(chat_id)).await; - if context - .sql - .execute( - "UPDATE chats \ - SET locations_send_begin=?, \ - locations_send_until=? \ - WHERE id=?", - paramsv![ - if 0 != seconds { now } else { 0 }, - if 0 != seconds { now + seconds } else { 0 }, - chat_id, - ], - ) + let is_sending_locations_before = is_sending_locations_to_chat(context, Some(chat_id)).await?; + context + .sql + .execute( + "UPDATE chats \ + SET locations_send_begin=?, \ + locations_send_until=? \ + WHERE id=?", + paramsv![ + if 0 != seconds { now } else { 0 }, + if 0 != seconds { now + seconds } else { 0 }, + chat_id, + ], + ) + .await?; + if 0 != seconds && !is_sending_locations_before { + let mut msg = Message::new(Viewtype::Text); + msg.text = Some(stock_str::msg_location_enabled(context).await); + msg.param.set_cmd(SystemMessage::LocationStreamingEnabled); + chat::send_msg(context, chat_id, &mut msg) .await - .is_ok() - { - if 0 != seconds && !is_sending_locations_before { - let mut msg = Message::new(Viewtype::Text); - msg.text = Some(stock_str::msg_location_enabled(context).await); - msg.param.set_cmd(SystemMessage::LocationStreamingEnabled); - chat::send_msg(context, chat_id, &mut msg) - .await - .unwrap_or_default(); - } else if 0 == seconds && is_sending_locations_before { - let stock_str = stock_str::msg_location_disabled(context).await; - chat::add_info_msg(context, chat_id, stock_str, now).await; - } - context.emit_event(EventType::ChatModified(chat_id)); - if 0 != seconds { - schedule_maybe_send_locations(context, false).await; - job::add( - context, - job::Job::new( - job::Action::MaybeSendLocationsEnded, - chat_id.to_u32(), - Params::new(), - seconds + 1, - ), - ) - .await; - } - } + .unwrap_or_default(); + } else if 0 == seconds && is_sending_locations_before { + let stock_str = stock_str::msg_location_disabled(context).await; + chat::add_info_msg(context, chat_id, stock_str, now).await; } + context.emit_event(EventType::ChatModified(chat_id)); + if 0 != seconds { + schedule_maybe_send_locations(context, false).await; + job::add( + context, + job::Job::new( + job::Action::MaybeSendLocationsEnded, + chat_id.to_u32(), + Params::new(), + seconds + 1, + ), + ) + .await; + } + Ok(()) } async fn schedule_maybe_send_locations(context: &Context, force_schedule: bool) { @@ -255,25 +256,31 @@ async fn schedule_maybe_send_locations(context: &Context, force_schedule: bool) /// /// If `chat_id` is `Some` only that chat is checked, otherwise returns `true` if any chat /// is sending locations. -pub async fn is_sending_locations_to_chat(context: &Context, chat_id: Option) -> bool { - match chat_id { - Some(chat_id) => context - .sql - .exists( - "SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;", - paramsv![chat_id, time()], - ) - .await - .unwrap_or_default(), - None => context - .sql - .exists( - "SELECT COUNT(id) FROM chats WHERE locations_send_until>?;", - paramsv![time()], - ) - .await - .unwrap_or_default(), - } +pub async fn is_sending_locations_to_chat( + context: &Context, + chat_id: Option, +) -> Result { + let exists = match chat_id { + Some(chat_id) => { + context + .sql + .exists( + "SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;", + paramsv![chat_id, time()], + ) + .await? + } + None => { + context + .sql + .exists( + "SELECT COUNT(id) FROM chats WHERE locations_send_until>?;", + paramsv![time()], + ) + .await? + } + }; + Ok(exists) } pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64) -> bool { @@ -288,7 +295,11 @@ pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64 "SELECT id FROM chats WHERE locations_send_until>?;", paramsv![time()], |row| row.get::<_, i32>(0), - |chats| chats.collect::, _>>().map_err(Into::into), + |chats| { + chats + .collect::, _>>() + .map_err(Into::into) + }, ) .await { @@ -325,7 +336,7 @@ pub async fn get_range( contact_id: Option, timestamp_from: i64, mut timestamp_to: i64, -) -> Result, Error> { +) -> Result> { if timestamp_to == 0 { timestamp_to = time() + 10; } @@ -400,7 +411,7 @@ fn is_marker(txt: &str) -> bool { } /// Deletes all locations from the database. -pub async fn delete_all(context: &Context) -> Result<(), Error> { +pub async fn delete_all(context: &Context) -> Result<()> { context .sql .execute("DELETE FROM locations;", paramsv![]) @@ -409,7 +420,7 @@ pub async fn delete_all(context: &Context) -> Result<(), Error> { Ok(()) } -pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32), Error> { +pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32)> { let mut last_added_location_id = 0; let self_addr = context @@ -517,7 +528,7 @@ pub async fn set_kml_sent_timestamp( context: &Context, chat_id: ChatId, timestamp: i64, -) -> Result<(), Error> { +) -> Result<()> { context .sql .execute( @@ -528,11 +539,7 @@ pub async fn set_kml_sent_timestamp( Ok(()) } -pub async fn set_msg_location_id( - context: &Context, - msg_id: MsgId, - location_id: u32, -) -> Result<(), Error> { +pub async fn set_msg_location_id(context: &Context, msg_id: MsgId, location_id: u32) -> Result<()> { context .sql .execute( @@ -550,7 +557,7 @@ pub async fn save( contact_id: u32, locations: &[Location], independent: bool, -) -> Result { +) -> Result { ensure!(!chat_id.is_special(), "Invalid chat id"); let mut newest_timestamp = 0; @@ -630,7 +637,7 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j }, |rows| { rows.filter_map(|v| v.transpose()) - .collect::, _>>() + .collect::, _>>() .map_err(Into::into) }, ) diff --git a/src/message.rs b/src/message.rs index ac9f70abf..1c9cd0345 100644 --- a/src/message.rs +++ b/src/message.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use std::convert::TryInto; -use anyhow::{ensure, format_err, Result}; +use anyhow::{ensure, format_err, Context as _, Result}; use async_std::path::{Path, PathBuf}; use deltachat_derive::{FromSql, ToSql}; use itertools::Itertools; @@ -1366,16 +1366,16 @@ pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result Result<()> { for msg_id in msg_ids.iter() { - if let Ok(msg) = Message::load_from_db(context, *msg_id).await { - if msg.location_id > 0 { - delete_poi_location(context, msg.location_id).await; - } - } - if let Err(err) = msg_id.trash(context).await { - error!(context, "Unable to trash message {}: {}", msg_id, err); + let msg = Message::load_from_db(context, *msg_id).await?; + if msg.location_id > 0 { + delete_poi_location(context, msg.location_id).await; } + msg_id + .trash(context) + .await + .with_context(|| format!("Unable to trash message {}", msg_id))?; job::add( context, job::Job::new(Action::DeleteMsgOnImap, msg_id.to_u32(), Params::new(), 0), @@ -1388,13 +1388,14 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) { chat_id: ChatId::new(0), msg_id: MsgId::new(0), }); - job::kill_action(context, Action::Housekeeping).await; + job::kill_action(context, Action::Housekeeping).await?; job::add( context, job::Job::new(Action::Housekeeping, 0, Params::new(), 10), ) .await; } + Ok(()) } async fn delete_poi_location(context: &Context, location_id: u32) -> bool { diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 403f96dfe..dbaeddac6 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -1084,7 +1084,7 @@ impl<'a> MimeFactory<'a> { parts.push(msg_kml_part); } - if location::is_sending_locations_to_chat(context, Some(self.msg.chat_id)).await { + if location::is_sending_locations_to_chat(context, Some(self.msg.chat_id)).await? { match self.get_location_kml_part(context).await { Ok(part) => parts.push(part), Err(err) => { diff --git a/src/quota.rs b/src/quota.rs index 2303f9ad5..60f690d03 100644 --- a/src/quota.rs +++ b/src/quota.rs @@ -98,13 +98,14 @@ fn get_highest_usage<'t>( impl Context { // Adds a job to update `quota.recent` - pub(crate) async fn schedule_quota_update(&self) { - job::kill_action(self, Action::UpdateRecentQuota).await; + pub(crate) async fn schedule_quota_update(&self) -> Result<()> { + job::kill_action(self, Action::UpdateRecentQuota).await?; job::add( self, job::Job::new(Action::UpdateRecentQuota, 0, Params::new(), 0), ) .await; + Ok(()) } /// Updates `quota.recent`, sets `quota.modified` to the current time diff --git a/src/scheduler.rs b/src/scheduler.rs index 09ebe0444..bd9065ff2 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -82,7 +82,11 @@ async fn inbox_loop(ctx: Context, started: Sender<()>, inbox_handlers: ImapConne let mut jobs_loaded = 0; let mut info = InterruptInfo::default(); loop { - match job::load_next(&ctx, Thread::Imap, &info).await { + match job::load_next(&ctx, Thread::Imap, &info) + .await + .ok() + .flatten() + { Some(job) if jobs_loaded <= 20 => { jobs_loaded += 1; job::perform_job(&ctx, job::Connection::Inbox(&mut connection), job).await; @@ -289,7 +293,11 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect let mut interrupt_info = Default::default(); loop { - match job::load_next(&ctx, Thread::Smtp, &interrupt_info).await { + match job::load_next(&ctx, Thread::Smtp, &interrupt_info) + .await + .ok() + .flatten() + { Some(job) => { info!(ctx, "executing smtp job"); job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await; diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index c110486ec..8aa54c5ed 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -504,11 +504,11 @@ impl Context { } if quota.modified + QUOTA_MAX_AGE_SECONDS < time() { - self.schedule_quota_update().await; + self.schedule_quota_update().await?; } } else { ret += "
  • One moment...
  • "; - self.schedule_quota_update().await; + self.schedule_quota_update().await?; } ret += ""; diff --git a/src/securejoin.rs b/src/securejoin.rs index fb7573a00..063df7fd2 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -635,7 +635,7 @@ pub(crate) async fn handle_securejoin_handshake( .await?; return Ok(HandshakeMessage::Ignore); } - Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinInvited).await; + Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinInvited).await?; info!(context, "Auth verified.",); secure_connection_established(context, contact_chat_id).await?; emit_event!(context, EventType::ContactsChanged(Some(contact_id))); diff --git a/src/securejoin/bobstate.rs b/src/securejoin/bobstate.rs index d4a0afffe..201462925 100644 --- a/src/securejoin/bobstate.rs +++ b/src/securejoin/bobstate.rs @@ -357,7 +357,7 @@ impl BobState { } mark_peer_as_verified(context, self.invite.fingerprint()).await?; Contact::scaleup_origin_by_id(context, self.invite.contact_id(), Origin::SecurejoinJoined) - .await; + .await?; emit_event!(context, EventType::ContactsChanged(None)); if let QrInvite::Group { .. } = self.invite { diff --git a/src/sql.rs b/src/sql.rs index fa376252d..9809ff936 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -598,7 +598,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> { ); } - context.schedule_quota_update().await; + context.schedule_quota_update().await?; if let Err(e) = context .set_config(Config::LastHousekeeping, Some(&time().to_string()))