From 2309c7ca13d071f789f9572e2dcb8bd0eecd757a Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 25 Sep 2021 13:02:30 +0000 Subject: [PATCH] Emit events from account manager Errors and warnings are emitted with a special 0 account ID. --- deltachat-ffi/deltachat.h | 2 +- deltachat-ffi/src/lib.rs | 63 +++++++++++++++++++++++++++++++-------- src/accounts.rs | 33 ++++++++++---------- src/events.rs | 4 --- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 332f9d4db..9848fc70d 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -4993,7 +4993,7 @@ char* dc_event_get_data2_str(dc_event_t* event); * * @memberof dc_event_t * @param event Event object as returned from dc_accounts_get_next_event(). - * @return account-id belonging to the event or 0 for errors. + * @return account-id belonging to the event, 0 for account manager errors. */ uint32_t dc_event_get_account_id(dc_event_t* event); diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index faf4ce11a..e66c5da30 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -3856,9 +3856,19 @@ pub unsafe extern "C" fn dc_accounts_select_account( } let accounts = &*accounts; - block_on(async move { accounts.write().await.select_account(id).await }) - .map(|_| 1) - .unwrap_or(0) + block_on(async move { + let mut accounts = accounts.write().await; + match accounts.select_account(id).await { + Ok(()) => 1, + Err(err) => { + accounts.emit_event(EventType::Error(format!( + "Failed to select account: {:#}", + err + ))); + 0 + } + } + }) } #[no_mangle] @@ -3870,7 +3880,19 @@ pub unsafe extern "C" fn dc_accounts_add_account(accounts: *mut dc_accounts_t) - let accounts = &mut *accounts; - block_on(async move { accounts.write().await.add_account().await }).unwrap_or(0) + block_on(async move { + let mut accounts = accounts.write().await; + match accounts.add_account().await { + Ok(id) => id, + Err(err) => { + accounts.emit_event(EventType::Error(format!( + "Failed to add account: {:#}", + err + ))); + 0 + } + } + }) } #[no_mangle] @@ -3885,9 +3907,19 @@ pub unsafe extern "C" fn dc_accounts_remove_account( let accounts = &mut *accounts; - block_on(async move { accounts.write().await.remove_account(id).await }) - .map(|_| 1) - .unwrap_or_else(|_| 0) + block_on(async move { + let mut accounts = accounts.write().await; + match accounts.remove_account(id).await { + Ok(()) => 1, + Err(err) => { + accounts.emit_event(EventType::Error(format!( + "Failed to remove account: {:#}", + err + ))); + 0 + } + } + }) } #[no_mangle] @@ -3904,14 +3936,21 @@ pub unsafe extern "C" fn dc_accounts_migrate_account( let dbfile = to_string_lossy(dbfile); block_on(async move { - accounts - .write() - .await + let mut accounts = accounts.write().await; + match accounts .migrate_account(async_std::path::PathBuf::from(dbfile)) .await + { + Ok(id) => id, + Err(err) => { + accounts.emit_event(EventType::Error(format!( + "Failed to migrate account: {:#}", + err + ))); + 0 + } + } }) - .map(|_| 1) - .unwrap_or_else(|_| 0) } #[no_mangle] diff --git a/src/accounts.rs b/src/accounts.rs index 65e5b0f3e..4885c0cab 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -13,7 +13,7 @@ use anyhow::{ensure, Context as _, Result}; use serde::{Deserialize, Serialize}; use crate::context::Context; -use crate::events::Event; +use crate::events::{Event, EventType, Events}; /// Account manager, that can handle multiple accounts in a single place. #[derive(Debug)] @@ -23,12 +23,8 @@ pub struct Accounts { accounts: BTreeMap, emitter: EventEmitter, - /// Sender side of the fake event channel. - /// - /// We never send any events over this channel, but hold it during the account manager lifetime - /// to prevent `EventEmitter` from returning `None` as long as account manager is alive, even if - /// it holds no accounts which could emit events. - fake_sender: Sender, + /// Event channel to emit account manager errors. + events: Events, } impl Accounts { @@ -65,9 +61,9 @@ impl Accounts { let emitter = EventEmitter::new(); - // Fake event stream to prevent event emitter from closing. - let (fake_sender, fake_receiver) = channel::bounded(1); - emitter.sender.send(fake_receiver).await?; + let events = Events::default(); + + emitter.sender.send(events.get_emitter()).await?; for account in accounts.values() { emitter.add_account(account).await?; @@ -78,7 +74,7 @@ impl Accounts { config, accounts, emitter, - fake_sender, + events, }) } @@ -262,6 +258,11 @@ impl Accounts { } } + /// Emits a single event. + pub fn emit_event(&self, event: EventType) { + self.events.emit(Event { id: 0, typ: event }) + } + /// Returns unified event emitter. pub async fn get_event_emitter(&self) -> EventEmitter { self.emitter.clone() @@ -272,13 +273,13 @@ impl Accounts { #[derive(Debug, Clone)] pub struct EventEmitter { /// Aggregate stream of events from all accounts. - stream: Arc>>>, + stream: Arc>>, /// Sender for the channel where new account emitters will be pushed. - sender: Sender>, + sender: Sender, /// Receiver for the channel where new account emitters will be pushed. - receiver: Receiver>, + receiver: Receiver, } impl EventEmitter { @@ -311,9 +312,7 @@ impl EventEmitter { /// Add event emitter of a new account to the aggregate event emitter. pub async fn add_account(&self, context: &Context) -> Result<()> { - self.sender - .send(context.get_event_emitter().into_inner()) - .await?; + self.sender.send(context.get_event_emitter()).await?; Ok(()) } } diff --git a/src/events.rs b/src/events.rs index 9356f9e5f..eb460d769 100644 --- a/src/events.rs +++ b/src/events.rs @@ -62,10 +62,6 @@ impl Events { pub struct EventEmitter(Receiver); impl EventEmitter { - pub(crate) fn into_inner(self) -> Receiver { - self.0 - } - /// Blocking recv of an event. Return `None` if the `Sender` has been droped. pub fn recv_sync(&self) -> Option { async_std::task::block_on(self.recv())