remove duplicate filter types

only use nostrdb::Filter

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2024-08-04 10:40:59 -07:00
parent 8c458f8f78
commit 9328ef2dff
18 changed files with 156 additions and 225 deletions

View File

@@ -6,7 +6,8 @@ use crate::{
};
use enostr::NoteId;
use nostrdb::Transaction;
use tracing::{info, warn};
use tracing::{error, info};
use uuid::Uuid;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum BarAction {
@@ -45,11 +46,11 @@ fn open_thread(
let root_id = crate::note::root_note_id_from_selected_id(app, txn, selected_note);
let thread_res = app.threads.thread_mut(&app.ndb, txn, root_id);
// The thread is stale, let's update it
let (thread, result) = match thread_res {
ThreadResult::Stale(thread) => {
// The thread is stale, let's update it
let notes = Thread::new_notes(&thread.view.notes, root_id, txn, &app.ndb);
let br = if notes.is_empty() {
let bar_result = if notes.is_empty() {
None
} else {
Some(BarResult::new_thread_notes(
@@ -63,8 +64,9 @@ fn open_thread(
// are already borrowing it mutably. Let's pass it as a
// result instead
//
// thread.view.insert(&notes);
(thread, br)
// thread.view.insert(&notes); <-- no
//
(thread, bar_result)
}
ThreadResult::Fresh(thread) => (thread, None),
@@ -73,18 +75,27 @@ fn open_thread(
// only start a subscription on nav and if we don't have
// an active subscription for this thread.
if thread.subscription().is_none() {
*thread.subscription_mut() = app.ndb.subscribe(Thread::filters(root_id)).ok();
let filters = Thread::filters(root_id);
*thread.subscription_mut() = app.ndb.subscribe(filters.clone()).ok();
if thread.remote_subscription().is_some() {
error!("Found active remote subscription when it was not expected");
} else {
let subid = Uuid::new_v4().to_string();
*thread.remote_subscription_mut() = Some(subid.clone());
app.pool.subscribe(subid, filters);
}
match thread.subscription() {
Some(_sub) => {
thread.subscribers += 1;
info!(
"Locally subscribing to thread. {} total active subscriptions, {} on this thread",
"Locally/remotely subscribing to thread. {} total active subscriptions, {} on this thread",
app.ndb.subscription_count(),
thread.subscribers,
);
}
None => warn!(
None => error!(
"Error subscribing locally to selected note '{}''s thread",
hex::encode(selected_note)
),

View File

@@ -17,15 +17,14 @@ use crate::ui::{self, AccountSelectionWidget, DesktopGlobalPopup};
use crate::ui::{DesktopSidePanel, RelayView, View};
use crate::Result;
use egui_nav::{Nav, NavAction};
use enostr::{Keypair, RelayPool, SecretKey};
use enostr::{ClientMessage, Keypair, RelayEvent, RelayMessage, RelayPool, SecretKey};
use std::cell::RefCell;
use std::rc::Rc;
use egui::{Context, Frame, Style};
use egui_extras::{Size, StripBuilder};
use enostr::{ClientMessage, Filter, Pubkey, RelayEvent, RelayMessage};
use nostrdb::{BlockType, Config, Mention, Ndb, Note, NoteKey, Transaction};
use nostrdb::{BlockType, Config, Filter, Mention, Ndb, Note, NoteKey, Transaction};
use std::collections::HashSet;
use std::hash::Hash;
@@ -102,23 +101,27 @@ fn send_initial_filters(damus: &mut Damus, relay_url: &str) {
let relay = &mut relay.relay;
if relay.url == relay_url {
for timeline in &damus.timelines {
let mut filter = timeline.filter.clone();
for f in &mut filter {
let filter = timeline.filter.clone();
let new_filters = filter.into_iter().map(|f| {
// limit the size of remote filters
let default_limit = enostr::Filter::default_remote_limit();
let lim = f.limit.unwrap_or(default_limit);
let default_limit = crate::filter::default_remote_limit();
let mut lim = f.limit().unwrap_or(default_limit);
let mut filter = f;
if lim > default_limit {
f.limit = Some(default_limit);
lim = default_limit;
filter = filter.limit_mut(lim);
}
let notes = timeline.notes(ViewFilter::NotesAndReplies);
if crate::filter::should_since_optimize(f.limit, notes.len()) {
crate::filter::since_optimize_filter(f, notes);
if crate::filter::should_since_optimize(lim, notes.len()) {
filter = crate::filter::since_optimize_filter(filter, notes);
} else {
warn!("Skipping since optimization for {:?}: number of local notes is less than limit, attempting to backfill.", f);
warn!("Skipping since optimization for {:?}: number of local notes is less than limit, attempting to backfill.", filter);
}
}
relay.subscribe(format!("initial{}", c), filter);
filter
}).collect();
relay.subscribe(format!("initial{}", c), new_filters);
c += 1;
}
return;
@@ -347,11 +350,7 @@ fn setup_profiling() {
fn setup_initial_nostrdb_subs(damus: &mut Damus) -> Result<()> {
let timelines = damus.timelines.len();
for i in 0..timelines {
let filters: Vec<nostrdb::Filter> = damus.timelines[i]
.filter
.iter()
.map(crate::filter::convert_enostr_filter)
.collect();
let filters = damus.timelines[i].filter.clone();
damus.timelines[i].subscription = Some(damus.ndb.subscribe(filters.clone())?);
let txn = Transaction::new(&damus.ndb)?;
debug!(
@@ -363,8 +362,8 @@ fn setup_initial_nostrdb_subs(damus: &mut Damus) -> Result<()> {
&txn,
filters,
damus.timelines[i].filter[0]
.limit
.unwrap_or(enostr::Filter::default_limit()) as i32,
.limit()
.unwrap_or(crate::filter::default_limit()) as i32,
)?;
let filters = {
@@ -465,22 +464,16 @@ fn get_unknown_ids_filter(ids: &[UnknownId<'_>]) -> Option<Vec<Filter>> {
let mut filters: Vec<Filter> = vec![];
let pks: Vec<Pubkey> = ids
.iter()
.flat_map(|id| id.is_pubkey().map(Pubkey::new))
.collect();
let pks: Vec<&[u8; 32]> = ids.iter().flat_map(|id| id.is_pubkey()).collect();
if !pks.is_empty() {
let pk_filter = Filter::new().authors(pks).kinds(vec![0]);
let pk_filter = Filter::new().authors(pks).kinds([0]).build();
filters.push(pk_filter);
}
let note_ids: Vec<enostr::NoteId> = ids
.iter()
.flat_map(|id| id.is_id().map(|id| enostr::NoteId::new(*id)))
.collect();
let note_ids: Vec<&[u8; 32]> = ids.iter().flat_map(|id| id.is_id()).collect();
if !note_ids.is_empty() {
filters.push(Filter::new().ids(note_ids));
filters.push(Filter::new().ids(note_ids).build());
}
Some(filters)
@@ -589,8 +582,8 @@ fn parse_args(args: &[String]) -> Args {
continue;
};
if let Ok(filter) = serde_json::from_str(filter) {
res.timelines.push(Timeline::new(filter));
if let Ok(filter) = Filter::from_json(filter) {
res.timelines.push(Timeline::new(vec![filter]));
} else {
error!("failed to parse filter '{}'", filter);
}
@@ -628,8 +621,11 @@ fn parse_args(args: &[String]) -> Args {
continue;
};
if let Ok(filter) = serde_json::from_slice(&data) {
res.timelines.push(Timeline::new(filter));
if let Some(filter) = std::str::from_utf8(&data)
.ok()
.and_then(|s| Filter::from_json(s).ok())
{
res.timelines.push(Timeline::new(vec![filter]));
} else {
error!("failed to parse filter in '{}'", filter_file);
}
@@ -639,8 +635,8 @@ fn parse_args(args: &[String]) -> Args {
}
if res.timelines.is_empty() {
let filter = serde_json::from_str(include_str!("../queries/timeline.json")).unwrap();
res.timelines.push(Timeline::new(filter));
let filter = Filter::from_json(include_str!("../queries/timeline.json")).unwrap();
res.timelines.push(Timeline::new(vec![filter]));
}
res
@@ -749,8 +745,8 @@ impl Damus {
pub fn mock<P: AsRef<Path>>(data_path: P, is_mobile: bool) -> Self {
let mut timelines: Vec<Timeline> = vec![];
let filter = serde_json::from_str(include_str!("../queries/global.json")).unwrap();
timelines.push(Timeline::new(filter));
let filter = Filter::from_json(include_str!("../queries/global.json")).unwrap();
timelines.push(Timeline::new(vec![filter]));
let imgcache_dir = data_path.as_ref().join(ImageCache::rel_datadir());
let _ = std::fs::create_dir_all(imgcache_dir.clone());

View File

@@ -1,72 +1,32 @@
use crate::note::NoteRef;
use nostrdb::Filter;
pub fn should_since_optimize(limit: Option<u16>, num_notes: usize) -> bool {
let limit = limit.unwrap_or(enostr::Filter::default_limit()) as usize;
pub fn should_since_optimize(limit: u64, num_notes: usize) -> bool {
// rough heuristic for bailing since optimization if we don't have enough notes
limit <= num_notes
limit as usize <= num_notes
}
pub fn since_optimize_filter_with(filter: &mut enostr::Filter, notes: &[NoteRef], since_gap: u64) {
pub fn since_optimize_filter_with(filter: Filter, notes: &[NoteRef], since_gap: u64) -> Filter {
// Get the latest entry in the events
if notes.is_empty() {
return;
return filter;
}
// get the latest note
let latest = notes[0];
let since = latest.created_at - since_gap;
// update the filters
filter.since = Some(since);
filter.since_mut(since)
}
pub fn since_optimize_filter(filter: &mut enostr::Filter, notes: &[NoteRef]) {
since_optimize_filter_with(filter, notes, 60);
pub fn since_optimize_filter(filter: Filter, notes: &[NoteRef]) -> Filter {
since_optimize_filter_with(filter, notes, 60)
}
pub fn convert_enostr_filter(filter: &enostr::Filter) -> nostrdb::Filter {
let mut nfilter = nostrdb::Filter::new();
if let Some(ref ids) = filter.ids {
nfilter = nfilter.ids(ids.iter().map(|a| *a.bytes()).collect());
}
if let Some(ref authors) = filter.authors {
let authors: Vec<[u8; 32]> = authors.iter().map(|a| *a.bytes()).collect();
nfilter = nfilter.authors(authors);
}
if let Some(ref kinds) = filter.kinds {
nfilter = nfilter.kinds(kinds.clone());
}
// #e
if let Some(ref events) = filter.events {
nfilter = nfilter.events(events.iter().map(|a| *a.bytes()).collect());
}
// #p
if let Some(ref pubkeys) = filter.pubkeys {
nfilter = nfilter.pubkeys(pubkeys.iter().map(|a| *a.bytes()).collect());
}
// #t
if let Some(ref hashtags) = filter.hashtags {
nfilter = nfilter.tags(hashtags.clone(), 't');
}
if let Some(since) = filter.since {
nfilter = nfilter.since(since);
}
if let Some(until) = filter.until {
nfilter = nfilter.until(until);
}
if let Some(limit) = filter.limit {
nfilter = nfilter.limit(limit.into());
}
nfilter.build()
pub fn default_limit() -> u64 {
250
}
pub fn default_remote_limit() -> u64 {
150
}

View File

@@ -10,6 +10,7 @@ use tracing::{debug, warn};
pub struct Thread {
pub view: TimelineTab,
sub: Option<Subscription>,
remote_sub: Option<String>,
pub subscribers: i32,
}
@@ -28,11 +29,13 @@ impl Thread {
let mut view = TimelineTab::new_with_capacity(ViewFilter::NotesAndReplies, cap);
view.notes = notes;
let sub: Option<Subscription> = None;
let remote_sub: Option<String> = None;
let subscribers: i32 = 0;
Thread {
view,
sub,
remote_sub,
subscribers,
}
}
@@ -83,14 +86,22 @@ impl Thread {
self.sub.as_ref()
}
pub fn remote_subscription(&self) -> Option<&String> {
self.remote_sub.as_ref()
}
pub fn remote_subscription_mut(&mut self) -> &mut Option<String> {
&mut self.remote_sub
}
pub fn subscription_mut(&mut self) -> &mut Option<Subscription> {
&mut self.sub
}
fn filters_raw(root: &[u8; 32]) -> Vec<FilterBuilder> {
vec![
nostrdb::Filter::new().kinds(vec![1]).event(root),
nostrdb::Filter::new().ids(vec![*root]).limit(1),
nostrdb::Filter::new().kinds([1]).event(root),
nostrdb::Filter::new().ids([root]).limit(1),
]
}

View File

@@ -7,8 +7,7 @@ use crate::{Damus, Result};
use crate::route::Route;
use egui_virtual_list::VirtualList;
use enostr::Filter;
use nostrdb::{Note, Subscription, Transaction};
use nostrdb::{Filter, Note, Subscription, Transaction};
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;