Emit events from account manager

Errors and warnings are emitted with a special 0 account ID.
This commit is contained in:
link2xt
2021-09-25 13:02:30 +00:00
parent 89d8b26192
commit 2309c7ca13
4 changed files with 68 additions and 34 deletions

View File

@@ -4993,7 +4993,7 @@ char* dc_event_get_data2_str(dc_event_t* event);
* *
* @memberof dc_event_t * @memberof dc_event_t
* @param event Event object as returned from dc_accounts_get_next_event(). * @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); uint32_t dc_event_get_account_id(dc_event_t* event);

View File

@@ -3856,9 +3856,19 @@ pub unsafe extern "C" fn dc_accounts_select_account(
} }
let accounts = &*accounts; let accounts = &*accounts;
block_on(async move { accounts.write().await.select_account(id).await }) block_on(async move {
.map(|_| 1) let mut accounts = accounts.write().await;
.unwrap_or(0) match accounts.select_account(id).await {
Ok(()) => 1,
Err(err) => {
accounts.emit_event(EventType::Error(format!(
"Failed to select account: {:#}",
err
)));
0
}
}
})
} }
#[no_mangle] #[no_mangle]
@@ -3870,7 +3880,19 @@ pub unsafe extern "C" fn dc_accounts_add_account(accounts: *mut dc_accounts_t) -
let accounts = &mut *accounts; 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] #[no_mangle]
@@ -3885,9 +3907,19 @@ pub unsafe extern "C" fn dc_accounts_remove_account(
let accounts = &mut *accounts; let accounts = &mut *accounts;
block_on(async move { accounts.write().await.remove_account(id).await }) block_on(async move {
.map(|_| 1) let mut accounts = accounts.write().await;
.unwrap_or_else(|_| 0) match accounts.remove_account(id).await {
Ok(()) => 1,
Err(err) => {
accounts.emit_event(EventType::Error(format!(
"Failed to remove account: {:#}",
err
)));
0
}
}
})
} }
#[no_mangle] #[no_mangle]
@@ -3904,14 +3936,21 @@ pub unsafe extern "C" fn dc_accounts_migrate_account(
let dbfile = to_string_lossy(dbfile); let dbfile = to_string_lossy(dbfile);
block_on(async move { block_on(async move {
accounts let mut accounts = accounts.write().await;
.write() match accounts
.await
.migrate_account(async_std::path::PathBuf::from(dbfile)) .migrate_account(async_std::path::PathBuf::from(dbfile))
.await .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] #[no_mangle]

View File

@@ -13,7 +13,7 @@ use anyhow::{ensure, Context as _, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::context::Context; 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. /// Account manager, that can handle multiple accounts in a single place.
#[derive(Debug)] #[derive(Debug)]
@@ -23,12 +23,8 @@ pub struct Accounts {
accounts: BTreeMap<u32, Context>, accounts: BTreeMap<u32, Context>,
emitter: EventEmitter, emitter: EventEmitter,
/// Sender side of the fake event channel. /// Event channel to emit account manager errors.
/// events: Events,
/// 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<crate::events::Event>,
} }
impl Accounts { impl Accounts {
@@ -65,9 +61,9 @@ impl Accounts {
let emitter = EventEmitter::new(); let emitter = EventEmitter::new();
// Fake event stream to prevent event emitter from closing. let events = Events::default();
let (fake_sender, fake_receiver) = channel::bounded(1);
emitter.sender.send(fake_receiver).await?; emitter.sender.send(events.get_emitter()).await?;
for account in accounts.values() { for account in accounts.values() {
emitter.add_account(account).await?; emitter.add_account(account).await?;
@@ -78,7 +74,7 @@ impl Accounts {
config, config,
accounts, accounts,
emitter, 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. /// Returns unified event emitter.
pub async fn get_event_emitter(&self) -> EventEmitter { pub async fn get_event_emitter(&self) -> EventEmitter {
self.emitter.clone() self.emitter.clone()
@@ -272,13 +273,13 @@ impl Accounts {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EventEmitter { pub struct EventEmitter {
/// Aggregate stream of events from all accounts. /// Aggregate stream of events from all accounts.
stream: Arc<RwLock<futures::stream::SelectAll<Receiver<crate::events::Event>>>>, stream: Arc<RwLock<futures::stream::SelectAll<crate::events::EventEmitter>>>,
/// Sender for the channel where new account emitters will be pushed. /// Sender for the channel where new account emitters will be pushed.
sender: Sender<Receiver<crate::events::Event>>, sender: Sender<crate::events::EventEmitter>,
/// Receiver for the channel where new account emitters will be pushed. /// Receiver for the channel where new account emitters will be pushed.
receiver: Receiver<Receiver<crate::events::Event>>, receiver: Receiver<crate::events::EventEmitter>,
} }
impl EventEmitter { impl EventEmitter {
@@ -311,9 +312,7 @@ impl EventEmitter {
/// Add event emitter of a new account to the aggregate event emitter. /// Add event emitter of a new account to the aggregate event emitter.
pub async fn add_account(&self, context: &Context) -> Result<()> { pub async fn add_account(&self, context: &Context) -> Result<()> {
self.sender self.sender.send(context.get_event_emitter()).await?;
.send(context.get_event_emitter().into_inner())
.await?;
Ok(()) Ok(())
} }
} }

View File

@@ -62,10 +62,6 @@ impl Events {
pub struct EventEmitter(Receiver<Event>); pub struct EventEmitter(Receiver<Event>);
impl EventEmitter { impl EventEmitter {
pub(crate) fn into_inner(self) -> Receiver<Event> {
self.0
}
/// Blocking recv of an event. Return `None` if the `Sender` has been droped. /// Blocking recv of an event. Return `None` if the `Sender` has been droped.
pub fn recv_sync(&self) -> Option<Event> { pub fn recv_sync(&self) -> Option<Event> {
async_std::task::block_on(self.recv()) async_std::task::block_on(self.recv())