accounts: move mute stuff to own module

Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
kernelkind
2025-06-25 16:24:27 -04:00
parent 10ed593b6d
commit e8d833bf89
3 changed files with 126 additions and 119 deletions

View File

@@ -1,14 +1,12 @@
use tracing::{debug, error, info};
use crate::account::mute::AccountMutedData;
use crate::account::relay::AccountRelayData;
use crate::{
AccountStorage, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds, UserAccount,
};
use crate::{AccountStorage, MuteFun, RelaySpec, SingleUnkIdAction, UnknownIds, UserAccount};
use enostr::{ClientMessage, FilledKeypair, Keypair, Pubkey, RelayPool};
use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction};
use nostrdb::{Ndb, Note, Transaction};
use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use uuid::Uuid;
// TODO: remove this
use std::sync::Arc;
@@ -46,120 +44,6 @@ pub struct AddAccountAction {
pub unk_id_action: SingleUnkIdAction,
}
pub struct AccountMutedData {
filter: Filter,
subid: Option<String>,
sub: Option<Subscription>,
muted: Arc<Muted>,
}
impl AccountMutedData {
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])
.kinds([10000])
.limit(1)
.build();
// 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;
let nks = ndb
.query(&txn, &[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);
AccountMutedData {
filter,
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() {
if let Ok(note) = ndb.get_note_by_key(txn, *nk) {
for tag in note.tags() {
match tag.get(0).and_then(|t| t.variant().str()) {
Some("p") => {
if let Some(id) = tag.get(1).and_then(|f| f.variant().id()) {
muted.pubkeys.insert(*id);
}
}
Some("t") => {
if let Some(str) = tag.get(1).and_then(|f| f.variant().str()) {
muted.hashtags.insert(str.to_string());
}
}
Some("word") => {
if let Some(str) = tag.get(1).and_then(|f| f.variant().str()) {
muted.words.insert(str.to_string());
}
}
Some("e") => {
if let Some(id) = tag.get(1).and_then(|f| f.variant().id()) {
muted.threads.insert(*id);
}
}
Some("alt") => {
// maybe we can ignore these?
}
Some(x) => error!("query_nip51_muted: unexpected tag: {}", x),
None => error!(
"query_nip51_muted: bad tag value: {:?}",
tag.get_unchecked(0).variant()
),
}
}
}
}
muted
}
}
pub struct AccountData {
pub(crate) relay: AccountRelayData,
pub(crate) muted: AccountMutedData,

View File

@@ -1,2 +1,3 @@
pub mod accounts;
pub mod mute;
pub mod relay;

View File

@@ -0,0 +1,122 @@
use std::sync::Arc;
use enostr::RelayPool;
use nostrdb::{Filter, Ndb, NoteKey, Subscription, Transaction};
use tracing::{debug, error};
use uuid::Uuid;
use crate::Muted;
pub(crate) struct AccountMutedData {
pub filter: Filter,
pub subid: Option<String>,
pub sub: Option<Subscription>,
pub muted: Arc<Muted>,
}
impl AccountMutedData {
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])
.kinds([10000])
.limit(1)
.build();
// 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;
let nks = ndb
.query(&txn, &[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);
AccountMutedData {
filter,
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;
}
pub(crate) fn harvest_nip51_muted(ndb: &Ndb, txn: &Transaction, nks: &[NoteKey]) -> Muted {
let mut muted = Muted::default();
for nk in nks.iter() {
if let Ok(note) = ndb.get_note_by_key(txn, *nk) {
for tag in note.tags() {
match tag.get(0).and_then(|t| t.variant().str()) {
Some("p") => {
if let Some(id) = tag.get(1).and_then(|f| f.variant().id()) {
muted.pubkeys.insert(*id);
}
}
Some("t") => {
if let Some(str) = tag.get(1).and_then(|f| f.variant().str()) {
muted.hashtags.insert(str.to_string());
}
}
Some("word") => {
if let Some(str) = tag.get(1).and_then(|f| f.variant().str()) {
muted.words.insert(str.to_string());
}
}
Some("e") => {
if let Some(id) = tag.get(1).and_then(|f| f.variant().id()) {
muted.threads.insert(*id);
}
}
Some("alt") => {
// maybe we can ignore these?
}
Some(x) => error!("query_nip51_muted: unexpected tag: {}", x),
None => error!(
"query_nip51_muted: bad tag value: {:?}",
tag.get_unchecked(0).variant()
),
}
}
}
}
muted
}
}