diff --git a/CHANGELOG.md b/CHANGELOG.md index c0a612175..4ece7eca4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,6 @@ # Changelog ## Unreleased - -### API-Changes -- add `debug_logging` setting #3296 - ### Changes - Disable Autocrypt & Authres-checking for mailing lists, because they don't work well with mailing lists #3765 @@ -17,6 +13,7 @@ - Add Python API to send reactions #3762 - jsonrpc: add message errors to MessageObject #3788 - jsonrpc: Add async Python client #3734 +- add `debug_logging` setting #3296 ### Fixes - Make sure malformed messsages will never block receiving further messages anymore #3771 diff --git a/benches/send_events.rs b/benches/send_events.rs index 0c7cea5f4..5005147ca 100644 --- a/benches/send_events.rs +++ b/benches/send_events.rs @@ -1,8 +1,8 @@ -use criterion::async_executor::AsyncStdExecutor; use criterion::{criterion_group, criterion_main, Criterion}; use deltachat::context::Context; -use deltachat::{info, Event, EventType}; +use deltachat::stock_str::StockStrings; +use deltachat::{info, Event, EventType, Events}; use tempfile::tempdir; async fn send_events_benchmark(context: &Context) { @@ -29,11 +29,17 @@ fn criterion_benchmark(c: &mut Criterion) { let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); let id = 100; - let context = - async_std::task::block_on(async { Context::new(dbfile.into(), id).await.unwrap() }); + let rt = tokio::runtime::Runtime::new().unwrap(); + + let context = rt.block_on(async { + Context::new(&dbfile, id, Events::new(), StockStrings::new()) + .await + .expect("failed to create context") + }); + let executor = tokio::runtime::Runtime::new().unwrap(); c.bench_function("Sending 1000 events", |b| { - b.to_async(AsyncStdExecutor) + b.to_async(&executor) .iter(|| send_events_benchmark(&context)) }); } diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index a03bd91e0..4a1e385e9 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -530,47 +530,8 @@ pub unsafe extern "C" fn dc_event_get_data1_int(event: *mut dc_event_t) -> libc: eprintln!("ignoring careless call to dc_event_get_data1_int()"); return 0; } - let event = &(*event).typ; - match event { - EventType::Info(_) - | EventType::SmtpConnected(_) - | EventType::ImapConnected(_) - | EventType::SmtpMessageSent(_) - | EventType::ImapMessageDeleted(_) - | EventType::ImapMessageMoved(_) - | EventType::NewBlobFile(_) - | EventType::DeletedBlobFile(_) - | EventType::Warning(_) - | EventType::Error(_) - | EventType::ConnectivityChanged - | EventType::SelfavatarChanged - | EventType::IncomingMsgBunch { .. } - | EventType::ErrorSelfNotInGroup(_) => 0, - EventType::MsgsChanged { chat_id, .. } - | EventType::ReactionsChanged { chat_id, .. } - | EventType::IncomingMsg { chat_id, .. } - | EventType::MsgsNoticed(chat_id) - | EventType::MsgDelivered { chat_id, .. } - | EventType::MsgFailed { chat_id, .. } - | EventType::MsgRead { chat_id, .. } - | EventType::ChatModified(chat_id) - | EventType::ChatEphemeralTimerModified { chat_id, .. } => chat_id.to_u32() as libc::c_int, - EventType::ContactsChanged(id) | EventType::LocationChanged(id) => { - let id = id.unwrap_or_default(); - id.to_u32() as libc::c_int - } - EventType::ConfigureProgress { progress, .. } | EventType::ImexProgress(progress) => { - *progress as libc::c_int - } - EventType::ImexFileWritten(_) => 0, - EventType::SecurejoinInviterProgress { contact_id, .. } - | EventType::SecurejoinJoinerProgress { contact_id, .. } => { - contact_id.to_u32() as libc::c_int - } - EventType::WebxdcStatusUpdate { msg_id, .. } => msg_id.to_u32() as libc::c_int, - EventType::WebxdcInstanceDeleted { msg_id, .. } => msg_id.to_u32() as libc::c_int, - } + event.get_data1_int() as libc::c_int } #[no_mangle] @@ -581,43 +542,10 @@ pub unsafe extern "C" fn dc_event_get_data2_int(event: *mut dc_event_t) -> libc: } let event = &(*event).typ; - - match event { - EventType::Info(_) - | EventType::SmtpConnected(_) - | EventType::ImapConnected(_) - | EventType::SmtpMessageSent(_) - | EventType::ImapMessageDeleted(_) - | EventType::ImapMessageMoved(_) - | EventType::NewBlobFile(_) - | EventType::DeletedBlobFile(_) - | EventType::Warning(_) - | EventType::Error(_) - | EventType::ErrorSelfNotInGroup(_) - | EventType::ContactsChanged(_) - | EventType::LocationChanged(_) - | EventType::ConfigureProgress { .. } - | EventType::ImexProgress(_) - | EventType::ImexFileWritten(_) - | EventType::MsgsNoticed(_) - | EventType::ConnectivityChanged - | EventType::WebxdcInstanceDeleted { .. } - | EventType::IncomingMsgBunch { .. } - | EventType::SelfavatarChanged => 0, - EventType::ChatModified(_) => 0, - EventType::MsgsChanged { msg_id, .. } - | EventType::ReactionsChanged { msg_id, .. } - | EventType::IncomingMsg { msg_id, .. } - | EventType::MsgDelivered { msg_id, .. } - | EventType::MsgFailed { msg_id, .. } - | EventType::MsgRead { msg_id, .. } => msg_id.to_u32() as libc::c_int, - EventType::SecurejoinInviterProgress { progress, .. } - | EventType::SecurejoinJoinerProgress { progress, .. } => *progress as libc::c_int, - EventType::ChatEphemeralTimerModified { timer, .. } => timer.to_u32() as libc::c_int, - EventType::WebxdcStatusUpdate { - status_update_serial, - .. - } => status_update_serial.to_u32() as libc::c_int, + if let Some(data2) = event.get_data2_int() { + data2 as libc::c_int + } else { + 0 } } @@ -629,48 +557,25 @@ pub unsafe extern "C" fn dc_event_get_data2_str(event: *mut dc_event_t) -> *mut } let event = &(*event).typ; - match event { + EventType::IncomingMsgBunch { msg_ids } => serde_json::to_string(msg_ids) + .unwrap_or_default() + .to_c_string() + .unwrap_or_default() + .into_raw(), EventType::ImexFileWritten(file) => { // Directly convert the PathBuf file to a CString, since both can contain invalid // UTF-8, but a Rust `String` can't let data2 = file.to_c_string().unwrap_or_default(); data2.into_raw() } - EventType::MsgsChanged { .. } - | EventType::ReactionsChanged { .. } - | EventType::IncomingMsg { .. } - | EventType::MsgsNoticed(_) - | EventType::MsgDelivered { .. } - | EventType::MsgFailed { .. } - | EventType::MsgRead { .. } - | EventType::ChatModified(_) - | EventType::ContactsChanged(_) - | EventType::LocationChanged(_) - | EventType::ImexProgress(_) - | EventType::SecurejoinInviterProgress { .. } - | EventType::SecurejoinJoinerProgress { .. } - | EventType::ConnectivityChanged - | EventType::SelfavatarChanged - | EventType::WebxdcStatusUpdate { .. } - | EventType::WebxdcInstanceDeleted { .. } - | EventType::ChatEphemeralTimerModified { .. } => ptr::null_mut(), - EventType::ConfigureProgress { comment, .. } => { - if let Some(comment) = comment { - comment.to_c_string().unwrap_or_default().into_raw() + _ => { + if let Some(data2) = event.get_data2_str() { + data2.to_c_string().unwrap_or_default().into_raw() } else { ptr::null_mut() } } - EventType::ImexFileWritten(file) => { - let data2 = file.to_c_string().unwrap_or_default(); - data2.into_raw() - } - EventType::IncomingMsgBunch { msg_ids } => serde_json::to_string(msg_ids) - .unwrap_or_default() - .to_c_string() - .unwrap_or_default() - .into_raw(), } } diff --git a/src/config.rs b/src/config.rs index 1d75600f5..46381ee2a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,7 +18,6 @@ use crate::message::{self, Message, MsgId, Viewtype}; use crate::mimefactory::RECOMMENDED_FILE_SIZE; use crate::provider::{get_provider_by_id, Provider}; use crate::tools::{get_abs_path, improve_single_line_input, EmailAddress}; -use crate::{chat, webxdc}; /// The available configuration keys. #[derive( @@ -197,7 +196,7 @@ pub enum Config { /// /// See `crate::authres::update_authservid_candidates`. AuthservIdCandidates, - + // TODO docs, deltachat.h /// Let the core save all events to the database. You should expose this as an advanced /// setting to the user. When they enable it, the core automatically adds a webxdc @@ -336,15 +335,15 @@ impl Context { Config::DebugLogging => { if value == Some("0") || value == Some("") || value == None { if let Some(webxdc_message_id) = - self.sql.get_raw_config_u32(Config::DebugLogging).await? + self.sql.get_raw_config_u32(Config::DebugLogging.as_ref()).await? { message::delete_msgs(self, &[MsgId::new(webxdc_message_id)]).await?; } - self.sql.set_raw_config(key, None).await?; + self.sql.set_raw_config(key.as_ref(), None).await?; self.debug_logging.store(0, atomic::Ordering::Relaxed); } else if self .sql - .get_raw_config_u32(Config::DebugLogging) + .get_raw_config_u32(Config::DebugLogging.as_ref()) .await? .unwrap_or(0) == 0 @@ -360,7 +359,7 @@ impl Context { ); let msg_id = chat::add_device_msg(self, None, Some(&mut instance)).await?; self.sql - .set_raw_config(key, Some(&msg_id.to_u32().to_string())) + .set_raw_config(key.as_ref(), Some(&msg_id.to_u32().to_string())) .await?; self.debug_logging .store(msg_id.to_u32(), atomic::Ordering::Relaxed); diff --git a/src/context.rs b/src/context.rs index 798353c6f..ffa86088d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -232,7 +232,7 @@ pub struct InnerContext { /// The text of the last error logged and emitted as an event. /// If the ui wants to display an error after a failure, /// `last_error` should be used to avoid races with the event thread. - pub(crate) last_error: RwLock, + pub(crate) last_error: std::sync::RwLock, pub(crate) debug_logging: AtomicU32, } @@ -364,7 +364,7 @@ impl Context { server_id: RwLock::new(None), creation_time: std::time::SystemTime::now(), last_full_folder_scan: Mutex::new(None), - last_error: RwLock::new("".to_string()), + last_error: std::sync::RwLock::new("".to_string()), debug_logging: AtomicU32::default(), }; @@ -464,7 +464,8 @@ impl Context { .as_millis() as i64; let context = self.clone(); - async_std::task::block_on(async move { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async move { let webxdc_instance_id = MsgId::new(debug_logging as u32); match context diff --git a/src/events.rs b/src/events.rs index 14064e8cc..14e008651 100644 --- a/src/events.rs +++ b/src/events.rs @@ -2,11 +2,9 @@ use std::path::PathBuf; -use async_std::channel::{self, Receiver, Sender, TrySendError}; -use async_std::path::PathBuf; +use async_channel::{self as channel, Receiver, Sender, TrySendError}; use num_traits::ToPrimitive; use serde_json::Value; -use strum::EnumProperty; use crate::chat::ChatId; use crate::contact::ContactId; @@ -110,27 +108,7 @@ pub struct Event { pub typ: EventType, } -impl Deref for Event { - type Target = EventType; - - fn deref(&self) -> &EventType { - &self.typ - } -} - -impl EventType { - /// Returns the corresponding Event ID. - /// - /// These are the IDs used in the `DC_EVENT_*` constants in `deltachat.h`. - pub fn as_id(&self) -> i32 { - self.get_str("id") - .expect("missing id") - .parse() - .expect("invalid id") - } -} - -#[derive(Debug, Clone, PartialEq, Eq, EnumProperty, Display)] +#[derive(Debug, Clone, PartialEq, Eq, Display)] pub enum EventType { /// The library-user may write an informational string to the log. /// @@ -309,7 +287,7 @@ pub enum EventType { /// 1000=Protocol finished for this contact. SecurejoinInviterProgress { contact_id: ContactId, - progress: u32, + progress: usize, }, /// Progress information of a secure-join handshake from the view of the joiner @@ -322,7 +300,7 @@ pub enum EventType { /// (Bob has verified alice and waits until Alice does the same for him) SecurejoinJoinerProgress { contact_id: ContactId, - progress: u32, + progress: usize, }, /// The connectivity to the server changed. @@ -345,12 +323,6 @@ pub enum EventType { } impl EventType { - /// Get data associated with an event object. - /// This is meant to be used for the FFI and serializing; Rust code - /// can usually just match on the EventType. - /// - /// data1 is always an int. - /// For events that have no number associacted with them, this returns 0. pub fn get_data1_int(&self) -> u32 { match self { EventType::Info(_) @@ -365,9 +337,10 @@ impl EventType { | EventType::Error(_) | EventType::ConnectivityChanged | EventType::SelfavatarChanged - | EventType::ErrorSelfNotInGroup(_) - | EventType::ImexFileWritten(_) => 0, + | EventType::IncomingMsgBunch { .. } + | EventType::ErrorSelfNotInGroup(_) => 0, EventType::MsgsChanged { chat_id, .. } + | EventType::ReactionsChanged { chat_id, .. } | EventType::IncomingMsg { chat_id, .. } | EventType::MsgsNoticed(chat_id) | EventType::MsgDelivered { chat_id, .. } @@ -376,25 +349,19 @@ impl EventType { | EventType::ChatModified(chat_id) | EventType::ChatEphemeralTimerModified { chat_id, .. } => chat_id.to_u32(), EventType::ContactsChanged(id) | EventType::LocationChanged(id) => { - let id = id.unwrap_or_default(); - id.to_u32() + id.unwrap_or_default().to_u32() } EventType::ConfigureProgress { progress, .. } | EventType::ImexProgress(progress) => { - progress.to_u32().unwrap_or_default() + (*progress).to_u32().unwrap_or_default() } + EventType::ImexFileWritten(_) => 0, EventType::SecurejoinInviterProgress { contact_id, .. } | EventType::SecurejoinJoinerProgress { contact_id, .. } => contact_id.to_u32(), EventType::WebxdcStatusUpdate { msg_id, .. } => msg_id.to_u32(), + EventType::WebxdcInstanceDeleted { msg_id, .. } => msg_id.to_u32(), } } - /// Get data associated with an event object. - /// - /// data2 sometimes is a string and sometimes an int; if it's a string or - /// there is no data2, this function returns `None`. - /// - /// This is meant to be used for the FFI and serializing; Rust code - /// can usually just `match` the EventType. pub fn get_data2_int(&self) -> Option { match self { EventType::Info(_) @@ -415,15 +382,18 @@ impl EventType { | EventType::ImexFileWritten(_) | EventType::MsgsNoticed(_) | EventType::ConnectivityChanged - | EventType::SelfavatarChanged - | EventType::ChatModified(_) => None, + | EventType::WebxdcInstanceDeleted { .. } + | EventType::IncomingMsgBunch { .. } + | EventType::ChatModified(_) + | EventType::SelfavatarChanged => None, EventType::MsgsChanged { msg_id, .. } + | EventType::ReactionsChanged { msg_id, .. } | EventType::IncomingMsg { msg_id, .. } | EventType::MsgDelivered { msg_id, .. } | EventType::MsgFailed { msg_id, .. } | EventType::MsgRead { msg_id, .. } => Some(msg_id.to_u32()), EventType::SecurejoinInviterProgress { progress, .. } - | EventType::SecurejoinJoinerProgress { progress, .. } => Some(*progress), + | EventType::SecurejoinJoinerProgress { progress, .. } => (*progress).to_u32(), EventType::ChatEphemeralTimerModified { timer, .. } => Some(timer.to_u32()), EventType::WebxdcStatusUpdate { status_update_serial, @@ -432,13 +402,6 @@ impl EventType { } } - /// Get data associated with an event object. - /// - /// data2 sometimes is a string and sometimes an int; if it's an int or - /// there is no data2, this function returns `None`. - /// - /// This is meant to be used for the FFI and serializing; Rust code - /// can usually just `match` the EventType. pub fn get_data2_str(&self) -> Option<&str> { match self { EventType::Info(msg) @@ -453,6 +416,7 @@ impl EventType { | EventType::Error(msg) | EventType::ErrorSelfNotInGroup(msg) => Some(msg), EventType::MsgsChanged { .. } + | EventType::ReactionsChanged { .. } | EventType::IncomingMsg { .. } | EventType::MsgsNoticed(_) | EventType::MsgDelivered { .. } @@ -467,10 +431,20 @@ impl EventType { | EventType::ConnectivityChanged | EventType::SelfavatarChanged | EventType::WebxdcStatusUpdate { .. } + | EventType::WebxdcInstanceDeleted { .. } | EventType::ChatEphemeralTimerModified { .. } => None, - EventType::ConfigureProgress { comment, .. } => comment.as_deref(), - // Note that `PathBuf::to_str()` returns None for invalid UTF-8: + EventType::ConfigureProgress { comment, .. } => { + if let Some(comment) = comment { + Some(comment) + } else { + None + } + } EventType::ImexFileWritten(file) => file.to_str(), + EventType::IncomingMsgBunch { .. } => { + //serde_json::to_string(msg_ids).ok().map(|str| str.as_str()) + Some("fix me!!") + } } } diff --git a/src/message.rs b/src/message.rs index bbf618058..97af3bb49 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1286,7 +1286,7 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { if context.get_config(Config::DebugLogging).await? == Some(msg_id.to_u32().to_string()) { context .sql - .set_raw_config(Config::DebugLogging, None) + .set_raw_config(Config::DebugLogging.as_ref(), None) .await?; context.debug_logging.store(0, atomic::Ordering::Relaxed); } @@ -1300,7 +1300,7 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { // wouldn't compile ("recursion in an `async fn`") context .sql - .set_raw_config(Config::LastHousekeeping, None) + .set_raw_config(Config::LastHousekeeping.as_ref(), None) .await?; } diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index 7fb7cc0d4..9162220ca 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -243,7 +243,7 @@ enum JoinerProgress { // Succeeded, } -impl From for u32 { +impl From for usize { fn from(progress: JoinerProgress) -> Self { match progress { JoinerProgress::Error => 0, diff --git a/src/sql.rs b/src/sql.rs index 709feabdb..83c6a21f4 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -343,7 +343,9 @@ impl Sql { info!(context, "Opened database {:?}.", self.dbfile); *self.is_encrypted.write().await = Some(passphrase_nonempty); - let debug_logging = self.get_raw_config_u32(Config::DebugLogging).await?; + let debug_logging = self + .get_raw_config_u32(Config::DebugLogging.as_ref()) + .await?; context .debug_logging .store(debug_logging.unwrap_or(0), atomic::Ordering::Relaxed); @@ -599,13 +601,13 @@ impl Sql { .map(|s| s.and_then(|s| s.parse().ok())) } - pub async fn get_raw_config_bool(&self, key: &str) -> Result { + pub async fn get_raw_config_u32(&self, key: &str) -> Result> { self.get_raw_config(key) .await .map(|s| s.and_then(|s| s.parse().ok())) } - pub async fn get_raw_config_bool(&self, key: impl AsRef) -> Result { + pub async fn get_raw_config_bool(&self, key: &str) -> Result { // Not the most obvious way to encode bool as string, but it is matter // of backward compatibility. let res = self.get_raw_config_int(key).await?; diff --git a/src/webxdc.rs b/src/webxdc.rs index d93732f80..b86141a1f 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -327,8 +327,6 @@ impl Context { .write_status_update_inner(&instance.id, status_update_item) .await?; - let status_update_serial = StatusUpdateSerial(u32::try_from(rowid)?); - if instance.viewtype == Viewtype::Webxdc { self.emit_event(EventType::WebxdcStatusUpdate { msg_id: instance.id,