notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit c99b99ed52571023f9f540ab4f0f81af5a18cd2e
parent 6c951d1a2973884c0bd2ef89cb09780ff00ad318
Author: kernelkind <kernelkind@gmail.com>
Date:   Tue,  8 Jul 2025 15:09:03 -0400

`AccountData`: decouple query from constructor

the ndb query must be as close to the subscription as possible to
avoid events falling through the cracks

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/notedeck/src/account/accounts.rs | 45++++++++++++++++++++++-----------------------
Mcrates/notedeck/src/account/mute.rs | 23+++++++++++++++--------
Mcrates/notedeck/src/account/relay.rs | 29++++++++++++++++-------------
Mcrates/notedeck/src/app.rs | 4++--
Mcrates/notedeck_columns/src/accounts/mod.rs | 9+++------
Mcrates/notedeck_columns/src/nav.rs | 2++
6 files changed, 60 insertions(+), 52 deletions(-)

diff --git a/crates/notedeck/src/account/accounts.rs b/crates/notedeck/src/account/accounts.rs @@ -42,8 +42,8 @@ impl Accounts { let (mut cache, unknown_id) = AccountCache::new(UserAccount::new( Keypair::only_pubkey(fallback), AccountData { - relay: AccountRelayData::new(ndb, txn, fallback.bytes()), - muted: AccountMutedData::new(ndb, txn, fallback.bytes()), + relay: AccountRelayData::new(fallback.bytes()), + muted: AccountMutedData::new(fallback.bytes()), }, )); @@ -55,7 +55,7 @@ impl Accounts { match reader.get_accounts() { Ok(accounts) => { for account in accounts { - add_account_from_storage(&mut cache, ndb, txn, account).process_action( + add_account_from_storage(&mut cache, account).process_action( unknown_ids, ndb, txn, @@ -75,8 +75,10 @@ impl Accounts { let relay_defaults = RelayDefaults::new(forced_relays); - let selected = cache.selected(); - let selected_data = &selected.data; + let selected = cache.selected_mut(); + let selected_data = &mut selected.data; + + selected_data.query(ndb, txn); let subs = { AccountSubs::new( @@ -116,12 +118,7 @@ impl Accounts { } #[must_use = "UnknownIdAction's must be handled. Use .process_unknown_id_action()"] - pub fn add_account( - &mut self, - ndb: &Ndb, - txn: &Transaction, - kp: Keypair, - ) -> Option<AddAccountResponse> { + pub fn add_account(&mut self, kp: Keypair) -> Option<AddAccountResponse> { let acc = if let Some(acc) = self.cache.get_mut(&kp.pubkey) { if kp.secret_key.is_none() || acc.key.secret_key.is_some() { tracing::info!("Already have account, not adding"); @@ -132,8 +129,8 @@ impl Accounts { AccType::Acc(&*acc) } else { let new_account_data = AccountData { - relay: AccountRelayData::new(ndb, txn, kp.pubkey.bytes()), - muted: AccountMutedData::new(ndb, txn, kp.pubkey.bytes()), + relay: AccountRelayData::new(kp.pubkey.bytes()), + muted: AccountMutedData::new(kp.pubkey.bytes()), }; AccType::Entry( self.cache @@ -212,6 +209,7 @@ impl Accounts { &mut self, pk_to_select: &Pubkey, ndb: &mut Ndb, + txn: &Transaction, pool: &mut RelayPool, ctx: &egui::Context, ) { @@ -225,6 +223,7 @@ impl Accounts { } } + self.get_selected_account_mut().data.query(ndb, txn); self.subs.swap_to( ndb, pool, @@ -336,11 +335,9 @@ fn create_wakeup(ctx: &egui::Context) -> impl Fn() + Send + Sync + Clone + 'stat fn add_account_from_storage( cache: &mut AccountCache, - ndb: &Ndb, - txn: &Transaction, user_account_serializable: UserAccountSerializable, ) -> SingleUnkIdAction { - let Some(acc) = get_acc_from_storage(ndb, txn, user_account_serializable) else { + let Some(acc) = get_acc_from_storage(user_account_serializable) else { return SingleUnkIdAction::NoAction; }; @@ -350,15 +347,11 @@ fn add_account_from_storage( SingleUnkIdAction::pubkey(pk) } -fn get_acc_from_storage( - ndb: &Ndb, - txn: &Transaction, - user_account_serializable: UserAccountSerializable, -) -> Option<UserAccount> { +fn get_acc_from_storage(user_account_serializable: UserAccountSerializable) -> Option<UserAccount> { let keypair = user_account_serializable.key; let new_account_data = AccountData { - relay: AccountRelayData::new(ndb, txn, keypair.pubkey.bytes()), - muted: AccountMutedData::new(ndb, txn, keypair.pubkey.bytes()), + relay: AccountRelayData::new(keypair.pubkey.bytes()), + muted: AccountMutedData::new(keypair.pubkey.bytes()), }; let mut wallet = None; @@ -400,6 +393,12 @@ impl AccountData { resp } + + /// Note: query should be called as close to the subscription as possible + pub(super) fn query(&mut self, ndb: &Ndb, txn: &Transaction) { + self.relay.query(ndb, txn); + self.muted.query(ndb, txn); + } } pub(super) enum AccountDataUpdate { diff --git a/crates/notedeck/src/account/mute.rs b/crates/notedeck/src/account/mute.rs @@ -11,7 +11,7 @@ pub(crate) struct AccountMutedData { } impl AccountMutedData { - pub fn new(ndb: &Ndb, txn: &Transaction, pubkey: &[u8; 32]) -> Self { + pub fn new(pubkey: &[u8; 32]) -> Self { // Construct a filter for the user's NIP-51 muted list let filter = Filter::new() .authors([pubkey]) @@ -19,21 +19,28 @@ impl AccountMutedData { .limit(1) .build(); + AccountMutedData { + filter, + muted: Arc::new(Muted::default()), + } + } + + pub(super) fn query(&mut self, ndb: &Ndb, txn: &Transaction) { // Query the ndb immediately to see if the user's muted list is already there - let lim = filter.limit().unwrap_or(crate::filter::default_limit()) as i32; + let lim = self + .filter + .limit() + .unwrap_or(crate::filter::default_limit()) as i32; let nks = ndb - .query(txn, &[filter.clone()], lim) + .query(txn, &[self.filter.clone()], lim) .expect("query user muted results") .iter() .map(|qr| qr.note_key) .collect::<Vec<NoteKey>>(); let muted = Self::harvest_nip51_muted(ndb, txn, &nks); - debug!("pubkey {}: initial muted {:?}", hex::encode(pubkey), muted); + debug!("initial muted {:?}", muted); - AccountMutedData { - filter, - muted: Arc::new(muted), - } + self.muted = Arc::new(muted); } pub(crate) fn harvest_nip51_muted(ndb: &Ndb, txn: &Transaction, nks: &[NoteKey]) -> Muted { diff --git a/crates/notedeck/src/account/relay.rs b/crates/notedeck/src/account/relay.rs @@ -14,7 +14,7 @@ pub(crate) struct AccountRelayData { } impl AccountRelayData { - pub fn new(ndb: &Ndb, txn: &Transaction, pubkey: &[u8; 32]) -> Self { + pub fn new(pubkey: &[u8; 32]) -> Self { // Construct a filter for the user's NIP-65 relay list let filter = Filter::new() .authors([pubkey]) @@ -22,26 +22,29 @@ impl AccountRelayData { .limit(1) .build(); + AccountRelayData { + filter, + local: BTreeSet::new(), + advertised: BTreeSet::new(), + } + } + + pub fn query(&mut self, ndb: &Ndb, txn: &Transaction) { // Query the ndb immediately to see if the user list is already there - let lim = filter.limit().unwrap_or(crate::filter::default_limit()) as i32; + let lim = self + .filter + .limit() + .unwrap_or(crate::filter::default_limit()) as i32; let nks = ndb - .query(txn, &[filter.clone()], lim) + .query(txn, &[self.filter.clone()], lim) .expect("query user relays results") .iter() .map(|qr| qr.note_key) .collect::<Vec<NoteKey>>(); let relays = Self::harvest_nip65_relays(ndb, txn, &nks); - debug!( - "pubkey {}: initial relays {:?}", - hex::encode(pubkey), - relays - ); + debug!("initial relays {:?}", relays); - AccountRelayData { - filter, - local: BTreeSet::new(), - advertised: relays.into_iter().collect(), - } + self.advertised = relays.into_iter().collect() } // standardize the format (ie, trailing slashes) to avoid dups diff --git a/crates/notedeck/src/app.rs b/crates/notedeck/src/app.rs @@ -203,7 +203,7 @@ impl Notedeck { { for key in &parsed_args.keys { info!("adding account: {}", &key.pubkey); - if let Some(resp) = accounts.add_account(&ndb, &txn, key.clone()) { + if let Some(resp) = accounts.add_account(key.clone()) { resp.unk_id_action .process_action(&mut unknown_ids, &ndb, &txn); } @@ -211,7 +211,7 @@ impl Notedeck { } if let Some(first) = parsed_args.keys.first() { - accounts.select_account(&first.pubkey, &mut ndb, &mut pool, ctx); + accounts.select_account(&first.pubkey, &mut ndb, &txn, &mut pool, ctx); } let img_cache = Images::new(img_cache_dir); diff --git a/crates/notedeck_columns/src/accounts/mod.rs b/crates/notedeck_columns/src/accounts/mod.rs @@ -94,7 +94,7 @@ pub fn render_accounts_route( } } AccountsRouteResponse::AddAccount(response) => { - let action = process_login_view_response(accounts, decks, col, ndb, response); + let action = process_login_view_response(accounts, decks, col, response); *login_state = Default::default(); let router = get_active_columns_mut(accounts, decks) .column_mut(col) @@ -143,20 +143,17 @@ pub fn process_login_view_response( manager: &mut Accounts, decks: &mut DecksCache, col: usize, - ndb: &Ndb, response: AccountLoginResponse, ) -> AddAccountAction { let (r, pubkey) = match response { AccountLoginResponse::CreateNew => { let kp = FullKeypair::generate().to_keypair(); let pubkey = kp.pubkey; - let txn = Transaction::new(ndb).expect("txn"); - (manager.add_account(ndb, &txn, kp), pubkey) + (manager.add_account(kp), pubkey) } AccountLoginResponse::LoginWith(keypair) => { let pubkey = keypair.pubkey; - let txn = Transaction::new(ndb).expect("txn"); - (manager.add_account(ndb, &txn, keypair), pubkey) + (manager.add_account(keypair), pubkey) } }; diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -78,9 +78,11 @@ impl SwitchingAction { match &self { SwitchingAction::Accounts(account_action) => match account_action { AccountsAction::Switch(switch_action) => { + let txn = Transaction::new(ctx.ndb).expect("txn"); ctx.accounts.select_account( &switch_action.switch_to, ctx.ndb, + &txn, ctx.pool, ui_ctx, );