Resultification

This commit is contained in:
link2xt
2021-09-04 18:51:59 +00:00
parent 3c43d790a3
commit 5f065b245f
17 changed files with 180 additions and 184 deletions

View File

@@ -1570,6 +1570,8 @@ pub unsafe extern "C" fn dc_delete_msgs(
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt); let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
block_on(message::delete_msgs(ctx, &msg_ids)) block_on(message::delete_msgs(ctx, &msg_ids))
.log_err(ctx, "failed dc_delete_msgs() call")
.ok();
} }
#[no_mangle] #[no_mangle]
@@ -2047,7 +2049,9 @@ pub unsafe extern "C" fn dc_send_locations_to_chat(
ctx, ctx,
ChatId::new(chat_id), ChatId::new(chat_id),
seconds as i64, seconds as i64,
)); ))
.log_err(ctx, "Failed dc_send_locations_to_chat()")
.ok();
} }
#[no_mangle] #[no_mangle]
@@ -2066,7 +2070,8 @@ pub unsafe extern "C" fn dc_is_sending_locations_to_chat(
Some(ChatId::new(chat_id)) 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] #[no_mangle]

View File

@@ -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!("Location streaming enabled.");
} }
println!("{} chats", cnt); println!("{} chats", cnt);
@@ -773,7 +773,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
&context, &context,
Some(sel_chat.as_ref().unwrap().get_id()) Some(sel_chat.as_ref().unwrap().get_id())
) )
.await, .await?,
); );
} }
"getlocations" => { "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(), sel_chat.as_ref().unwrap().get_id(),
seconds, seconds,
) )
.await; .await?;
println!( println!(
"Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.", "Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.",
sel_chat.as_ref().unwrap().get_id(), 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 <msg-id> missing."); ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
let mut ids = [MsgId::new(0); 1]; let mut ids = [MsgId::new(0); 1];
ids[0] = MsgId::new(arg1.parse()?); ids[0] = MsgId::new(arg1.parse()?);
message::delete_msgs(&context, &ids).await; message::delete_msgs(&context, &ids).await?;
} }
"listcontacts" | "contacts" | "listverified" => { "listcontacts" | "contacts" | "listverified" => {
let contacts = Contact::get_all( let contacts = Contact::get_all(

View File

@@ -183,7 +183,7 @@ impl ChatId {
|| contact_id == DC_CONTACT_ID_SELF || contact_id == DC_CONTACT_ID_SELF
{ {
let chat_id = ChatId::get_for_contact(context, contact_id).await?; 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 chat_id
} else { } else {
warn!( warn!(
@@ -284,7 +284,7 @@ impl ChatId {
for contact_id in get_chat_contacts(context, self).await? { for contact_id in get_chat_contacts(context, self).await? {
if contact_id != DC_CONTACT_ID_SELF { if contact_id != DC_CONTACT_ID_SELF {
Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat) Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat)
.await; .await?;
} }
} }
} }
@@ -497,7 +497,7 @@ impl ChatId {
chat_id: ChatId::new(0), 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); let j = job::Job::new(Action::Housekeeping, 0, Params::new(), 10);
job::add(context, j).await; 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<()> { pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuration) -> Result<()> {
ensure!(!chat_id.is_special(), "Invalid chat ID"); ensure!(!chat_id.is_special(), "Invalid chat ID");
if context context
.sql .sql
.execute( .execute(
"UPDATE chats SET muted_until=? WHERE id=?;", "UPDATE chats SET muted_until=? WHERE id=?;",
paramsv![duration, chat_id], paramsv![duration, chat_id],
) )
.await .await
.is_ok() .context(format!("Failed to set mute duration for {}", chat_id))?;
{ context.emit_event(EventType::ChatModified(chat_id));
context.emit_event(EventType::ChatModified(chat_id));
} else {
bail!("Failed to set mute duration, chat might not exist -");
}
Ok(()) Ok(())
} }
@@ -3252,7 +3248,9 @@ mod tests {
assert!(chat.get_profile_image(&t).await.unwrap().is_some()); assert!(chat.get_profile_image(&t).await.unwrap().is_some());
// delete device message, make sure it is not added again // 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; let msg1 = message::Message::load_from_db(&t, *msg1_id.as_ref().unwrap()).await;
assert!(msg1.is_err() || msg1.unwrap().chat_id.is_trash()); assert!(msg1.is_err() || msg1.unwrap().chat_id.is_trash());
let msg3_id = add_device_msg(&t, Some("any-label"), Some(&mut msg2)).await; let msg3_id = add_device_msg(&t, Some("any-label"), Some(&mut msg2)).await;

View File

@@ -317,7 +317,7 @@ impl Context {
.set_raw_config(key, value) .set_raw_config(key, value)
.await .await
.map_err(Into::into); .map_err(Into::into);
job::schedule_resync(self).await; job::schedule_resync(self).await?;
ret ret
} }
_ => { _ => {

View File

@@ -1109,15 +1109,19 @@ impl Contact {
.unwrap_or_default() .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 context
.sql .sql
.execute( .execute(
"UPDATE contacts SET origin=? WHERE id=? AND origin<?;", "UPDATE contacts SET origin=? WHERE id=? AND origin<?;",
paramsv![origin, contact_id as i32, origin], paramsv![origin, contact_id as i32, origin],
) )
.await .await?;
.is_ok() Ok(())
} }
} }

View File

@@ -618,7 +618,7 @@ async fn add_parts(
// we do not want any chat to be created implicitly. Because of the origin-scale-up, // we do not want any chat to be created implicitly. Because of the origin-scale-up,
// the contact requests will pop up and this should be just fine. // the contact requests will pop up and this should be just fine.
Contact::scaleup_origin_by_id(context, from_id, Origin::IncomingReplyTo) Contact::scaleup_origin_by_id(context, from_id, Origin::IncomingReplyTo)
.await; .await?;
info!( info!(
context, context,
"Message is a reply to a known message, mark sender as known.", "Message is a reply to a known message, mark sender as known.",

View File

@@ -583,7 +583,7 @@ impl Imap {
folder, old_uid_next, uid_next, new_uid_validity, folder, old_uid_next, uid_next, new_uid_validity,
); );
set_uid_next(context, folder, uid_next).await?; set_uid_next(context, folder, uid_next).await?;
job::schedule_resync(context).await; job::schedule_resync(context).await?;
} }
uid_next != old_uid_next // If uid_next changed, there are new emails uid_next != old_uid_next // If uid_next changed, there are new emails
} else { } else {
@@ -636,7 +636,7 @@ impl Imap {
set_uid_next(context, folder, new_uid_next).await?; set_uid_next(context, folder, new_uid_next).await?;
set_uidvalidity(context, folder, new_uid_validity).await?; set_uidvalidity(context, folder, new_uid_validity).await?;
if old_uid_validity != 0 || old_uid_next != 0 { if old_uid_validity != 0 || old_uid_next != 0 {
job::schedule_resync(context).await; job::schedule_resync(context).await?;
} }
info!( info!(
context, context,

View File

@@ -2,12 +2,11 @@
//! //!
//! This module implements a job queue maintained in the SQLite database //! This module implements a job queue maintained in the SQLite database
//! and job types. //! and job types.
use std::fmt;
use std::future::Future; use std::future::Future;
use std::{fmt, time::Duration};
use anyhow::{bail, ensure, format_err, Context as _, Error, Result}; use anyhow::{bail, ensure, format_err, Context as _, Error, Result};
use async_smtp::smtp::response::{Category, Code, Detail}; use async_smtp::smtp::response::{Category, Code, Detail};
use async_std::task::sleep;
use deltachat_derive::{FromSql, ToSql}; use deltachat_derive::{FromSql, ToSql};
use itertools::Itertools; use itertools::Itertools;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
@@ -815,12 +814,12 @@ impl Job {
} }
/// Delete all pending jobs with the given action. /// Delete all pending jobs with the given action.
pub async fn kill_action(context: &Context, action: Action) -> bool { pub async fn kill_action(context: &Context, action: Action) -> Result<()> {
context context
.sql .sql
.execute("DELETE FROM jobs WHERE action=?;", paramsv![action]) .execute("DELETE FROM jobs WHERE action=?;", paramsv![action])
.await .await?;
.is_ok() Ok(())
} }
/// Remove jobs with specified IDs. /// Remove jobs with specified IDs.
@@ -1183,13 +1182,14 @@ async fn send_mdn(context: &Context, msg: &Message) -> Result<()> {
Ok(()) Ok(())
} }
pub(crate) async fn schedule_resync(context: &Context) { pub(crate) async fn schedule_resync(context: &Context) -> Result<()> {
kill_action(context, Action::ResyncFolders).await; kill_action(context, Action::ResyncFolders).await?;
add( add(
context, context,
Job::new(Action::ResyncFolders, 0, Params::new(), 0), Job::new(Action::ResyncFolders, 0, Params::new(), 0),
) )
.await; .await;
Ok(())
} }
/// Creates a job. /// Creates a job.
@@ -1238,21 +1238,15 @@ pub async fn add(context: &Context, job: Job) {
} }
} }
async fn load_housekeeping_job(context: &Context) -> Option<Job> { async fn load_housekeeping_job(context: &Context) -> Result<Option<Job>> {
let last_time = match context.get_config_i64(Config::LastHousekeeping).await { let last_time = context.get_config_i64(Config::LastHousekeeping).await?;
Ok(last_time) => last_time,
Err(err) => {
warn!(context, "failed to load housekeeping config: {:?}", err);
return None;
}
};
let next_time = last_time + (60 * 60 * 24); let next_time = last_time + (60 * 60 * 24);
if next_time <= time() { if next_time <= time() {
kill_action(context, Action::Housekeeping).await; kill_action(context, Action::Housekeeping).await?;
Some(Job::new(Action::Housekeeping, 0, Params::new(), 0)) Ok(Some(Job::new(Action::Housekeeping, 0, Params::new(), 0)))
} else { } else {
None Ok(None)
} }
} }
@@ -1266,20 +1260,9 @@ pub(crate) async fn load_next(
context: &Context, context: &Context,
thread: Thread, thread: Thread,
info: &InterruptInfo, info: &InterruptInfo,
) -> Option<Job> { ) -> Result<Option<Job>> {
info!(context, "loading job for {}-thread", thread); 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 query;
let params; let params;
let t = time(); let t = time();
@@ -1346,51 +1329,38 @@ LIMIT 1;
info!(context, "cleaning up job, because of {}", err); info!(context, "cleaning up job, because of {}", err);
// TODO: improve by only doing a single query // TODO: improve by only doing a single query
match context let id = context
.sql .sql
.query_row(query, params.clone(), |row| row.get::<_, i32>(0)) .query_row(query, params.clone(), |row| row.get::<_, i32>(0))
.await .await
{ .context("Failed to retrieve invalid job ID from the database")?;
Ok(id) => { context
if let Err(err) = context .sql
.sql .execute("DELETE FROM jobs WHERE id=?;", paramsv![id])
.execute("DELETE FROM jobs WHERE id=?;", paramsv![id]) .await
.await .with_context(|| format!("Failed to delete invalid job {}", id))?;
{
warn!(context, "failed to delete job {}: {:?}", id, err);
}
}
Err(err) => {
error!(context, "failed to retrieve invalid job from DB: {}", err);
break None;
}
}
} }
} }
}; };
match thread { match thread {
Thread::Unknown => { Thread::Unknown => {
error!(context, "unknown thread for job"); bail!("unknown thread for job")
None
} }
Thread::Imap => { Thread::Imap => {
if let Some(job) = job { if let Some(job) = job {
if job.action < Action::DeleteMsgOnImap { if job.action < Action::DeleteMsgOnImap {
load_imap_deletion_job(context) Ok(load_imap_deletion_job(context).await?.or(Some(job)))
.await
.unwrap_or_default()
.or(Some(job))
} else { } else {
Some(job) Ok(Some(job))
} }
} else if let Some(job) = load_imap_deletion_job(context).await.unwrap_or_default() { } else if let Some(job) = load_imap_deletion_job(context).await? {
Some(job) Ok(Some(job))
} else { } 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_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 // We want to ensure that loading jobs skips over jobs which
// fails to load from the database instead of failing to load // fails to load from the database instead of failing to load
// all jobs. // all jobs.
@@ -1433,7 +1403,7 @@ mod tests {
Thread::from(Action::MoveMsg), Thread::from(Action::MoveMsg),
&InterruptInfo::new(false, None), &InterruptInfo::new(false, None),
) )
.await; .await?;
// The housekeeping job should be loaded as we didn't run housekeeping in the last day: // The housekeeping job should be loaded as we didn't run housekeeping in the last day:
assert_eq!(jobs.unwrap().action, Action::Housekeeping); assert_eq!(jobs.unwrap().action, Action::Housekeeping);
@@ -1443,12 +1413,13 @@ mod tests {
Thread::from(Action::MoveMsg), Thread::from(Action::MoveMsg),
&InterruptInfo::new(false, None), &InterruptInfo::new(false, None),
) )
.await; .await?;
assert!(jobs.is_some()); assert!(jobs.is_some());
Ok(())
} }
#[async_std::test] #[async_std::test]
async fn test_load_next_job_one() { async fn test_load_next_job_one() -> Result<()> {
let t = TestContext::new().await; let t = TestContext::new().await;
insert_job(&t, 1, true).await; insert_job(&t, 1, true).await;
@@ -1458,7 +1429,8 @@ mod tests {
Thread::from(Action::MoveMsg), Thread::from(Action::MoveMsg),
&InterruptInfo::new(false, None), &InterruptInfo::new(false, None),
) )
.await; .await?;
assert!(jobs.is_some()); assert!(jobs.is_some());
Ok(())
} }
} }

View File

@@ -1,7 +1,7 @@
//! Location handling. //! Location handling.
use std::convert::TryFrom; use std::convert::TryFrom;
use anyhow::{ensure, Error}; use anyhow::{ensure, Result};
use bitflags::bitflags; use bitflags::bitflags;
use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use quick_xml::events::{BytesEnd, BytesStart, BytesText};
@@ -63,7 +63,7 @@ impl Kml {
Default::default() Default::default()
} }
pub fn parse(context: &Context, to_parse: &[u8]) -> Result<Self, Error> { pub fn parse(context: &Context, to_parse: &[u8]) -> Result<Self> {
ensure!(to_parse.len() <= 1024 * 1024, "kml-file is too large"); ensure!(to_parse.len() <= 1024 * 1024, "kml-file is too large");
let mut reader = quick_xml::Reader::from_reader(to_parse); 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. /// 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(); 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?;
let is_sending_locations_before = context
is_sending_locations_to_chat(context, Some(chat_id)).await; .sql
if context .execute(
.sql "UPDATE chats \
.execute( SET locations_send_begin=?, \
"UPDATE chats \ locations_send_until=? \
SET locations_send_begin=?, \ WHERE id=?",
locations_send_until=? \ paramsv![
WHERE id=?", if 0 != seconds { now } else { 0 },
paramsv![ if 0 != seconds { now + seconds } else { 0 },
if 0 != seconds { now } else { 0 }, chat_id,
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 .await
.is_ok() .unwrap_or_default();
{ } else if 0 == seconds && is_sending_locations_before {
if 0 != seconds && !is_sending_locations_before { let stock_str = stock_str::msg_location_disabled(context).await;
let mut msg = Message::new(Viewtype::Text); chat::add_info_msg(context, chat_id, stock_str, now).await;
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;
}
}
} }
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) { 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 /// If `chat_id` is `Some` only that chat is checked, otherwise returns `true` if any chat
/// is sending locations. /// is sending locations.
pub async fn is_sending_locations_to_chat(context: &Context, chat_id: Option<ChatId>) -> bool { pub async fn is_sending_locations_to_chat(
match chat_id { context: &Context,
Some(chat_id) => context chat_id: Option<ChatId>,
.sql ) -> Result<bool> {
.exists( let exists = match chat_id {
"SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;", Some(chat_id) => {
paramsv![chat_id, time()], context
) .sql
.await .exists(
.unwrap_or_default(), "SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;",
None => context paramsv![chat_id, time()],
.sql )
.exists( .await?
"SELECT COUNT(id) FROM chats WHERE locations_send_until>?;", }
paramsv![time()], None => {
) context
.await .sql
.unwrap_or_default(), .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 { 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>?;", "SELECT id FROM chats WHERE locations_send_until>?;",
paramsv![time()], paramsv![time()],
|row| row.get::<_, i32>(0), |row| row.get::<_, i32>(0),
|chats| chats.collect::<Result<Vec<_>, _>>().map_err(Into::into), |chats| {
chats
.collect::<std::result::Result<Vec<_>, _>>()
.map_err(Into::into)
},
) )
.await .await
{ {
@@ -325,7 +336,7 @@ pub async fn get_range(
contact_id: Option<u32>, contact_id: Option<u32>,
timestamp_from: i64, timestamp_from: i64,
mut timestamp_to: i64, mut timestamp_to: i64,
) -> Result<Vec<Location>, Error> { ) -> Result<Vec<Location>> {
if timestamp_to == 0 { if timestamp_to == 0 {
timestamp_to = time() + 10; timestamp_to = time() + 10;
} }
@@ -400,7 +411,7 @@ fn is_marker(txt: &str) -> bool {
} }
/// Deletes all locations from the database. /// Deletes all locations from the database.
pub async fn delete_all(context: &Context) -> Result<(), Error> { pub async fn delete_all(context: &Context) -> Result<()> {
context context
.sql .sql
.execute("DELETE FROM locations;", paramsv![]) .execute("DELETE FROM locations;", paramsv![])
@@ -409,7 +420,7 @@ pub async fn delete_all(context: &Context) -> Result<(), Error> {
Ok(()) 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 mut last_added_location_id = 0;
let self_addr = context let self_addr = context
@@ -517,7 +528,7 @@ pub async fn set_kml_sent_timestamp(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
timestamp: i64, timestamp: i64,
) -> Result<(), Error> { ) -> Result<()> {
context context
.sql .sql
.execute( .execute(
@@ -528,11 +539,7 @@ pub async fn set_kml_sent_timestamp(
Ok(()) Ok(())
} }
pub async fn set_msg_location_id( pub async fn set_msg_location_id(context: &Context, msg_id: MsgId, location_id: u32) -> Result<()> {
context: &Context,
msg_id: MsgId,
location_id: u32,
) -> Result<(), Error> {
context context
.sql .sql
.execute( .execute(
@@ -550,7 +557,7 @@ pub async fn save(
contact_id: u32, contact_id: u32,
locations: &[Location], locations: &[Location],
independent: bool, independent: bool,
) -> Result<u32, Error> { ) -> Result<u32> {
ensure!(!chat_id.is_special(), "Invalid chat id"); ensure!(!chat_id.is_special(), "Invalid chat id");
let mut newest_timestamp = 0; let mut newest_timestamp = 0;
@@ -630,7 +637,7 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j
}, },
|rows| { |rows| {
rows.filter_map(|v| v.transpose()) rows.filter_map(|v| v.transpose())
.collect::<Result<Vec<_>, _>>() .collect::<std::result::Result<Vec<_>, _>>()
.map_err(Into::into) .map_err(Into::into)
}, },
) )

View File

@@ -3,7 +3,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::convert::TryInto; 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 async_std::path::{Path, PathBuf};
use deltachat_derive::{FromSql, ToSql}; use deltachat_derive::{FromSql, ToSql};
use itertools::Itertools; use itertools::Itertools;
@@ -1366,16 +1366,16 @@ pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result<Vec<u8
Ok(headers) Ok(headers)
} }
pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) { pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
for msg_id in msg_ids.iter() { for msg_id in msg_ids.iter() {
if let Ok(msg) = Message::load_from_db(context, *msg_id).await { let msg = Message::load_from_db(context, *msg_id).await?;
if msg.location_id > 0 { if msg.location_id > 0 {
delete_poi_location(context, msg.location_id).await; 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);
} }
msg_id
.trash(context)
.await
.with_context(|| format!("Unable to trash message {}", msg_id))?;
job::add( job::add(
context, context,
job::Job::new(Action::DeleteMsgOnImap, msg_id.to_u32(), Params::new(), 0), 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), chat_id: ChatId::new(0),
msg_id: MsgId::new(0), msg_id: MsgId::new(0),
}); });
job::kill_action(context, Action::Housekeeping).await; job::kill_action(context, Action::Housekeeping).await?;
job::add( job::add(
context, context,
job::Job::new(Action::Housekeeping, 0, Params::new(), 10), job::Job::new(Action::Housekeeping, 0, Params::new(), 10),
) )
.await; .await;
} }
Ok(())
} }
async fn delete_poi_location(context: &Context, location_id: u32) -> bool { async fn delete_poi_location(context: &Context, location_id: u32) -> bool {

View File

@@ -1084,7 +1084,7 @@ impl<'a> MimeFactory<'a> {
parts.push(msg_kml_part); 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 { match self.get_location_kml_part(context).await {
Ok(part) => parts.push(part), Ok(part) => parts.push(part),
Err(err) => { Err(err) => {

View File

@@ -98,13 +98,14 @@ fn get_highest_usage<'t>(
impl Context { impl Context {
// Adds a job to update `quota.recent` // Adds a job to update `quota.recent`
pub(crate) async fn schedule_quota_update(&self) { pub(crate) async fn schedule_quota_update(&self) -> Result<()> {
job::kill_action(self, Action::UpdateRecentQuota).await; job::kill_action(self, Action::UpdateRecentQuota).await?;
job::add( job::add(
self, self,
job::Job::new(Action::UpdateRecentQuota, 0, Params::new(), 0), job::Job::new(Action::UpdateRecentQuota, 0, Params::new(), 0),
) )
.await; .await;
Ok(())
} }
/// Updates `quota.recent`, sets `quota.modified` to the current time /// Updates `quota.recent`, sets `quota.modified` to the current time

View File

@@ -82,7 +82,11 @@ async fn inbox_loop(ctx: Context, started: Sender<()>, inbox_handlers: ImapConne
let mut jobs_loaded = 0; let mut jobs_loaded = 0;
let mut info = InterruptInfo::default(); let mut info = InterruptInfo::default();
loop { 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 => { Some(job) if jobs_loaded <= 20 => {
jobs_loaded += 1; jobs_loaded += 1;
job::perform_job(&ctx, job::Connection::Inbox(&mut connection), job).await; 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(); let mut interrupt_info = Default::default();
loop { 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) => { Some(job) => {
info!(ctx, "executing smtp job"); info!(ctx, "executing smtp job");
job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await; job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await;

View File

@@ -504,11 +504,11 @@ impl Context {
} }
if quota.modified + QUOTA_MAX_AGE_SECONDS < time() { if quota.modified + QUOTA_MAX_AGE_SECONDS < time() {
self.schedule_quota_update().await; self.schedule_quota_update().await?;
} }
} else { } else {
ret += "<li>One moment...</li>"; ret += "<li>One moment...</li>";
self.schedule_quota_update().await; self.schedule_quota_update().await?;
} }
ret += "</ul>"; ret += "</ul>";

View File

@@ -635,7 +635,7 @@ pub(crate) async fn handle_securejoin_handshake(
.await?; .await?;
return Ok(HandshakeMessage::Ignore); 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.",); info!(context, "Auth verified.",);
secure_connection_established(context, contact_chat_id).await?; secure_connection_established(context, contact_chat_id).await?;
emit_event!(context, EventType::ContactsChanged(Some(contact_id))); emit_event!(context, EventType::ContactsChanged(Some(contact_id)));

View File

@@ -357,7 +357,7 @@ impl BobState {
} }
mark_peer_as_verified(context, self.invite.fingerprint()).await?; mark_peer_as_verified(context, self.invite.fingerprint()).await?;
Contact::scaleup_origin_by_id(context, self.invite.contact_id(), Origin::SecurejoinJoined) Contact::scaleup_origin_by_id(context, self.invite.contact_id(), Origin::SecurejoinJoined)
.await; .await?;
emit_event!(context, EventType::ContactsChanged(None)); emit_event!(context, EventType::ContactsChanged(None));
if let QrInvite::Group { .. } = self.invite { if let QrInvite::Group { .. } = self.invite {

View File

@@ -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 if let Err(e) = context
.set_config(Config::LastHousekeeping, Some(&time().to_string())) .set_config(Config::LastHousekeeping, Some(&time().to_string()))