notedeck

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

commit 0b4545d598d18a94e495d43802372f8fef48a72d
parent c765b031e9bcab4c807636a60eb3a846fa69f314
Author: William Casarin <jb55@jb55.com>
Date:   Mon,  8 Sep 2025 15:01:52 -0700

filter: reservoir sample the algo feed

so its not the same static 15 pubkeys

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
MCargo.lock | 15++++++++-------
MCargo.toml | 1+
Mcrates/notedeck/Cargo.toml | 1+
Mcrates/notedeck/src/filter.rs | 51+++++++++++++++++++++++----------------------------
4 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -193,7 +193,7 @@ dependencies = [ "objc2-foundation 0.3.1", "parking_lot", "percent-encoding", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "x11rb", ] @@ -246,7 +246,7 @@ dependencies = [ "enumflags2", "futures-channel", "futures-util", - "rand 0.9.1", + "rand 0.9.2", "raw-window-handle", "serde", "serde_repr", @@ -3542,6 +3542,7 @@ dependencies = [ "profiling", "puffin", "puffin_egui", + "rand 0.9.2", "regex", "secp256k1 0.30.0", "serde", @@ -3683,7 +3684,7 @@ dependencies = [ "nostrdb", "notedeck", "notedeck_ui", - "rand 0.9.1", + "rand 0.9.2", "serde", "serde_json", "sha2", @@ -4603,7 +4604,7 @@ dependencies = [ "bytes", "getrandom 0.3.3", "lru-slab", - "rand 0.9.1", + "rand 0.9.2", "ring", "rustc-hash 2.1.1", "rustls", @@ -4657,9 +4658,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -6278,7 +6279,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.1", + "rand 0.9.2", "rustls", "rustls-pki-types", "sha1", diff --git a/Cargo.toml b/Cargo.toml @@ -19,6 +19,7 @@ chrono = "0.4.40" base32 = "0.4.0" base64 = "0.22.1" rmpv = "1.3.0" +rand = "0.9.2" bech32 = { version = "0.11", default-features = false } bitflags = "2.5.0" dirs = "5.0.1" diff --git a/crates/notedeck/Cargo.toml b/crates/notedeck/Cargo.toml @@ -51,6 +51,7 @@ bitflags = { workspace = true } regex = "1" chrono = { workspace = true } indexmap = {workspace = true} +rand = {workspace = true} crossbeam-channel = "0.5" [dev-dependencies] diff --git a/crates/notedeck/src/filter.rs b/crates/notedeck/src/filter.rs @@ -289,48 +289,43 @@ pub fn last_n_per_pubkey_from_tags( kind: u64, notes_per_pubkey: u64, ) -> Result<Vec<Filter>, Error> { + use rand::Rng; + let mut filters: Vec<Filter> = vec![]; + let mut rng = rand::rng(); - for tag in note.tags() { - // TODO: fix arbitrary MAX_FILTER limit in nostrdb - if filters.len() == 15 { - break; - } + // TODO: fix arbitrary MAX_FILTER limit in nostrdb + const LIMIT: usize = 15; + for (i, tag) in note.tags().iter().enumerate() { if tag.count() < 2 { continue; } - let t = if let Some(t) = tag.get_unchecked(0).variant().str() { - t - } else { + let Some("p") = tag.get_str(0) else { continue; }; - if t == "p" { - let author = if let Some(author) = tag.get_unchecked(1).variant().id() { - author - } else { - continue; - }; + let Some(author) = tag.get_id(1) else { + continue; + }; + let mk_filter = || { let mut filter = Filter::new(); - filter.start_authors_field()?; - filter.add_id_element(author)?; + let _ = filter.start_authors_field(); + let _ = filter.add_id_element(author); filter.end_field(); - filters.push(filter.kinds([kind]).limit(notes_per_pubkey).build()); - } else if t == "t" { - let hashtag = if let Some(hashtag) = tag.get_unchecked(1).variant().str() { - hashtag - } else { - continue; - }; + filter.kinds([kind]).limit(notes_per_pubkey).build() + }; - let mut filter = Filter::new(); - filter.start_tags_field('t')?; - filter.add_str_element(hashtag)?; - filter.end_field(); - filters.push(filter.kinds([kind]).limit(notes_per_pubkey).build()); + // since we're limited due to a nostrdb bug, we reservoir sample to keep things interesting + if filters.len() < LIMIT { + filters.push(mk_filter()); + } else { + let j = rng.random_range(0..=i); + if j < LIMIT { + filters[j] = mk_filter(); + } } }