Merge explicitly activate and deactivate account relay/muted list #678

Ken Sedgwick (4):
      drive-by compiler warning fixes
      improve debug logging, comments, and variable names for clarity
      explicitly activate and deactivate account relay list subs
      explicitly activate and deactivate account muted list subs
This commit is contained in:
William Casarin
2025-02-07 11:07:14 -08:00
2 changed files with 144 additions and 58 deletions

View File

@@ -37,7 +37,7 @@ pub enum AccountsAction {
pub struct AccountRelayData {
filter: Filter,
subid: String,
subid: Option<String>,
sub: Option<Subscription>,
local: BTreeSet<RelaySpec>, // used locally but not advertised
advertised: BTreeSet<RelaySpec>, // advertised via NIP-65
@@ -56,7 +56,7 @@ pub struct AddAccountAction {
}
impl AccountRelayData {
pub fn new(ndb: &Ndb, pool: &mut RelayPool, pubkey: &[u8; 32]) -> Self {
pub fn new(ndb: &Ndb, pubkey: &[u8; 32]) -> Self {
// Construct a filter for the user's NIP-65 relay list
let filter = Filter::new()
.authors([pubkey])
@@ -64,11 +64,6 @@ impl AccountRelayData {
.limit(1)
.build();
// Local ndb subscription
let ndbsub = ndb
.subscribe(&[filter.clone()])
.expect("ndb relay list subscription");
// Query the ndb immediately to see if the user list is already there
let txn = Transaction::new(ndb).expect("transaction");
let lim = filter.limit().unwrap_or(crate::filter::default_limit()) as i32;
@@ -85,21 +80,51 @@ impl AccountRelayData {
relays
);
// Id for future remote relay subscriptions
let subid = Uuid::new_v4().to_string();
// Add remote subscription to existing relays
pool.subscribe(subid.clone(), vec![filter.clone()]);
AccountRelayData {
filter,
subid,
sub: Some(ndbsub),
subid: None,
sub: None,
local: BTreeSet::new(),
advertised: relays.into_iter().collect(),
}
}
// make this account the current selected account
pub fn activate(&mut self, ndb: &Ndb, pool: &mut RelayPool) {
debug!("activating relay sub {}", self.filter.json().unwrap());
assert_eq!(self.subid, None, "subid already exists");
assert_eq!(self.sub, None, "sub already exists");
// local subscription
let sub = ndb
.subscribe(&[self.filter.clone()])
.expect("ndb relay list subscription");
// remote subscription
let subid = Uuid::new_v4().to_string();
pool.subscribe(subid.clone(), vec![self.filter.clone()]);
self.sub = Some(sub);
self.subid = Some(subid);
}
// this account is no longer the selected account
pub fn deactivate(&mut self, ndb: &mut Ndb, pool: &mut RelayPool) {
debug!("deactivating relay sub {}", self.filter.json().unwrap());
assert_ne!(self.subid, None, "subid doesn't exist");
assert_ne!(self.sub, None, "sub doesn't exist");
// remote subscription
pool.unsubscribe(self.subid.as_ref().unwrap().clone());
// local subscription
ndb.unsubscribe(self.sub.unwrap())
.expect("ndb relay list unsubscribe");
self.sub = None;
self.subid = None;
}
// standardize the format (ie, trailing slashes) to avoid dups
pub fn canonicalize_url(url: &str) -> String {
match Url::parse(url) {
@@ -162,13 +187,13 @@ impl AccountRelayData {
pub struct AccountMutedData {
filter: Filter,
subid: String,
subid: Option<String>,
sub: Option<Subscription>,
muted: Arc<Muted>,
}
impl AccountMutedData {
pub fn new(ndb: &Ndb, pool: &mut RelayPool, pubkey: &[u8; 32]) -> Self {
pub fn new(ndb: &Ndb, pubkey: &[u8; 32]) -> Self {
// Construct a filter for the user's NIP-51 muted list
let filter = Filter::new()
.authors([pubkey])
@@ -176,11 +201,6 @@ impl AccountMutedData {
.limit(1)
.build();
// Local ndb subscription
let ndbsub = ndb
.subscribe(&[filter.clone()])
.expect("ndb muted subscription");
// Query the ndb immediately to see if the user's muted list is already there
let txn = Transaction::new(ndb).expect("transaction");
let lim = filter.limit().unwrap_or(crate::filter::default_limit()) as i32;
@@ -193,20 +213,50 @@ impl AccountMutedData {
let muted = Self::harvest_nip51_muted(ndb, &txn, &nks);
debug!("pubkey {}: initial muted {:?}", hex::encode(pubkey), muted);
// Id for future remote relay subscriptions
let subid = Uuid::new_v4().to_string();
// Add remote subscription to existing relays
pool.subscribe(subid.clone(), vec![filter.clone()]);
AccountMutedData {
filter,
subid,
sub: Some(ndbsub),
subid: None,
sub: None,
muted: Arc::new(muted),
}
}
// make this account the current selected account
pub fn activate(&mut self, ndb: &Ndb, pool: &mut RelayPool) {
debug!("activating muted sub {}", self.filter.json().unwrap());
assert_eq!(self.subid, None, "subid already exists");
assert_eq!(self.sub, None, "sub already exists");
// local subscription
let sub = ndb
.subscribe(&[self.filter.clone()])
.expect("ndb muted subscription");
// remote subscription
let subid = Uuid::new_v4().to_string();
pool.subscribe(subid.clone(), vec![self.filter.clone()]);
self.sub = Some(sub);
self.subid = Some(subid);
}
// this account is no longer the selected account
pub fn deactivate(&mut self, ndb: &mut Ndb, pool: &mut RelayPool) {
debug!("deactivating muted sub {}", self.filter.json().unwrap());
assert_ne!(self.subid, None, "subid doesn't exist");
assert_ne!(self.sub, None, "sub doesn't exist");
// remote subscription
pool.unsubscribe(self.subid.as_ref().unwrap().clone());
// local subscription
ndb.unsubscribe(self.sub.unwrap())
.expect("ndb muted unsubscribe");
self.sub = None;
self.subid = None;
}
fn harvest_nip51_muted(ndb: &Ndb, txn: &Transaction, nks: &[NoteKey]) -> Muted {
let mut muted = Muted::default();
for nk in nks.iter() {
@@ -432,13 +482,12 @@ impl Accounts {
}
}
pub fn get_selected_account_data(&self) -> Option<&AccountData> {
if let Some(account) = self.get_selected_account() {
if let Some(account_data) = self.account_data.get(account.pubkey.bytes()) {
return Some(account_data);
}
}
None
pub fn get_selected_account_data(&mut self) -> Option<&mut AccountData> {
let account_pubkey = {
let account = self.get_selected_account()?;
*account.pubkey.bytes()
};
self.account_data.get_mut(&account_pubkey)
}
pub fn select_account(&mut self, index: usize) {
@@ -470,18 +519,25 @@ impl Accounts {
pub fn send_initial_filters(&mut self, pool: &mut RelayPool, relay_url: &str) {
for data in self.account_data.values() {
pool.send_to(
&ClientMessage::req(data.relay.subid.clone(), vec![data.relay.filter.clone()]),
relay_url,
);
pool.send_to(
&ClientMessage::req(data.muted.subid.clone(), vec![data.muted.filter.clone()]),
relay_url,
);
// send the active account's relay list subscription
if let Some(relay_subid) = &data.relay.subid {
pool.send_to(
&ClientMessage::req(relay_subid.clone(), vec![data.relay.filter.clone()]),
relay_url,
);
}
// send the active account's muted subscription
if let Some(muted_subid) = &data.muted.subid {
pool.send_to(
&ClientMessage::req(muted_subid.clone(), vec![data.muted.filter.clone()]),
relay_url,
);
}
}
}
// Returns added and removed accounts
// Return accounts which have no account_data yet (added) and accounts
// which have still data but are no longer in our account list (removed).
fn delta_accounts(&self) -> (Vec<[u8; 32]>, Vec<[u8; 32]>) {
let mut added = Vec::new();
for pubkey in self.accounts.iter().map(|a| a.pubkey.bytes()) {
@@ -498,13 +554,13 @@ impl Accounts {
(added, removed)
}
fn handle_added_account(&mut self, ndb: &Ndb, pool: &mut RelayPool, pubkey: &[u8; 32]) {
fn handle_added_account(&mut self, ndb: &Ndb, pubkey: &[u8; 32]) {
debug!("handle_added_account {}", hex::encode(pubkey));
// Create the user account data
let new_account_data = AccountData {
relay: AccountRelayData::new(ndb, pool, pubkey),
muted: AccountMutedData::new(ndb, pool, pubkey),
relay: AccountRelayData::new(ndb, pubkey),
muted: AccountMutedData::new(ndb, pubkey),
};
self.account_data.insert(*pubkey, new_account_data);
}
@@ -552,8 +608,9 @@ impl Accounts {
wakeup: impl Fn() + Send + Sync + Clone + 'static,
) {
debug!(
"updating relay configuration for currently selected account {:?}",
"updating relay configuration for currently selected {:?}",
self.currently_selected_account
.map(|i| hex::encode(self.accounts.get(i).unwrap().pubkey.bytes()))
);
// If forced relays are set use them only
@@ -600,37 +657,66 @@ impl Accounts {
debug!("current relays: {:?}", pool.urls());
}
pub fn update(&mut self, ndb: &Ndb, pool: &mut RelayPool, ctx: &egui::Context) {
pub fn update(&mut self, ndb: &mut Ndb, pool: &mut RelayPool, ctx: &egui::Context) {
// IMPORTANT - This function is called in the UI update loop,
// make sure it is fast when idle
// On the initial update the relays need config even if nothing changes below
let mut relays_changed = self.needs_relay_config;
let mut need_reconfig = self.needs_relay_config;
let ctx2 = ctx.clone();
let wakeup = move || {
ctx2.request_repaint();
};
// Do we need to deactivate any existing account subs?
for (ndx, account) in self.accounts.iter().enumerate() {
if Some(ndx) != self.currently_selected_account {
// this account is not currently selected
if let Some(data) = self.account_data.get_mut(account.pubkey.bytes()) {
if data.relay.sub.is_some() {
// this account has relay subs, deactivate them
data.relay.deactivate(ndb, pool);
}
if data.muted.sub.is_some() {
// this account has muted subs, deactivate them
data.muted.deactivate(ndb, pool);
}
}
}
}
// Were any accounts added or removed?
let (added, removed) = self.delta_accounts();
for pk in added {
self.handle_added_account(ndb, pool, &pk);
relays_changed = true;
self.handle_added_account(ndb, &pk);
need_reconfig = true;
}
for pk in removed {
self.handle_removed_account(&pk);
relays_changed = true;
need_reconfig = true;
}
// Did any accounts receive updates (ie NIP-65 relay lists)
relays_changed = self.poll_for_updates(ndb) || relays_changed;
need_reconfig = self.poll_for_updates(ndb) || need_reconfig;
// If needed, update the relay configuration
if relays_changed {
if need_reconfig {
self.update_relay_configuration(pool, wakeup);
self.needs_relay_config = false;
}
// Do we need to activate account subs?
if let Some(data) = self.get_selected_account_data() {
if data.relay.sub.is_none() {
// the currently selected account doesn't have relay subs, activate them
data.relay.activate(ndb, pool);
}
if data.muted.sub.is_none() {
// the currently selected account doesn't have muted subs, activate them
data.muted.activate(ndb, pool);
}
}
}
pub fn get_full<'a>(&'a self, pubkey: &[u8; 32]) -> Option<FilledKeypair<'a>> {

View File

@@ -69,7 +69,7 @@ impl eframe::App for Notedeck {
puffin::GlobalProfiler::lock().new_frame();
// handle account updates
self.accounts.update(&self.ndb, &mut self.pool, ctx);
self.accounts.update(&mut self.ndb, &mut self.pool, ctx);
main_panel(&ctx.style(), crate::ui::is_narrow(ctx)).show(ctx, |ui| {
// render app