filter: create filter from contact list
This adds a method for creating filters from contact lists. We will be using this for creating follow timelines. Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -37,6 +37,7 @@ impl fmt::Display for SubscriptionError {
|
|||||||
pub enum Error {
|
pub enum Error {
|
||||||
SubscriptionError(SubscriptionError),
|
SubscriptionError(SubscriptionError),
|
||||||
LoadFailed,
|
LoadFailed,
|
||||||
|
EmptyContactList,
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
Nostr(enostr::Error),
|
Nostr(enostr::Error),
|
||||||
Ndb(nostrdb::Error),
|
Ndb(nostrdb::Error),
|
||||||
@@ -53,6 +54,9 @@ impl fmt::Display for Error {
|
|||||||
Self::LoadFailed => {
|
Self::LoadFailed => {
|
||||||
write!(f, "load failed")
|
write!(f, "load failed")
|
||||||
}
|
}
|
||||||
|
Self::EmptyContactList => {
|
||||||
|
write!(f, "empty contact list")
|
||||||
|
}
|
||||||
Self::Nostr(e) => write!(f, "{e}"),
|
Self::Nostr(e) => write!(f, "{e}"),
|
||||||
Self::Ndb(e) => write!(f, "{e}"),
|
Self::Ndb(e) => write!(f, "{e}"),
|
||||||
Self::Image(e) => write!(f, "{e}"),
|
Self::Image(e) => write!(f, "{e}"),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::note::NoteRef;
|
use crate::note::NoteRef;
|
||||||
use nostrdb::Filter;
|
use crate::{Error, Result};
|
||||||
|
use nostrdb::{Filter, FilterBuilder, Note};
|
||||||
|
|
||||||
pub fn should_since_optimize(limit: u64, num_notes: usize) -> bool {
|
pub fn should_since_optimize(limit: u64, num_notes: usize) -> bool {
|
||||||
// rough heuristic for bailing since optimization if we don't have enough notes
|
// rough heuristic for bailing since optimization if we don't have enough notes
|
||||||
@@ -30,3 +31,65 @@ pub fn default_limit() -> u64 {
|
|||||||
pub fn default_remote_limit() -> u64 {
|
pub fn default_remote_limit() -> u64 {
|
||||||
150
|
150
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a filter from tags. This can be used to create a filter
|
||||||
|
/// from a contact list
|
||||||
|
pub fn filter_from_tags(note: &Note) -> Result<FilterBuilder> {
|
||||||
|
let mut filter = Filter::new();
|
||||||
|
let tags = note.tags();
|
||||||
|
let mut authors: Vec<&[u8; 32]> = Vec::with_capacity(tags.count() as usize);
|
||||||
|
let mut hashtags: Vec<&str> = vec![];
|
||||||
|
|
||||||
|
for tag in tags {
|
||||||
|
if tag.count() < 2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = if let Some(t) = tag.get_unchecked(0).variant().str() {
|
||||||
|
t
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if t == "p" {
|
||||||
|
let author = if let Some(author) = tag.get_unchecked(1).variant().id() {
|
||||||
|
author
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
authors.push(author);
|
||||||
|
} else if t == "t" {
|
||||||
|
let hashtag = if let Some(hashtag) = tag.get_unchecked(1).variant().str() {
|
||||||
|
hashtag
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
hashtags.push(hashtag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if authors.is_empty() && hashtags.is_empty() {
|
||||||
|
return Err(Error::EmptyContactList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we hit these ooms, we need to expand filter buffer size
|
||||||
|
if !authors.is_empty() {
|
||||||
|
filter.start_authors_field()?;
|
||||||
|
for author in authors {
|
||||||
|
filter.add_id_element(author)?;
|
||||||
|
}
|
||||||
|
filter.end_field();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hashtags.is_empty() {
|
||||||
|
filter.start_tags_field('t')?;
|
||||||
|
for hashtag in hashtags {
|
||||||
|
filter.add_str_element(hashtag)?;
|
||||||
|
}
|
||||||
|
filter.end_field();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(filter)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::app::{get_unknown_note_ids, UnknownId};
|
use crate::app::{get_unknown_note_ids, UnknownId};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
use crate::filter;
|
||||||
use crate::note::NoteRef;
|
use crate::note::NoteRef;
|
||||||
use crate::notecache::CachedNote;
|
use crate::notecache::CachedNote;
|
||||||
use crate::{Damus, Result};
|
use crate::{Damus, Result};
|
||||||
@@ -285,6 +286,13 @@ pub struct Timeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Timeline {
|
impl Timeline {
|
||||||
|
/// Create a timeline from a contact list
|
||||||
|
pub fn follows(contact_list: &Note) -> Result<Self> {
|
||||||
|
Ok(Timeline::new(vec![filter::filter_from_tags(contact_list)?
|
||||||
|
.kinds([1])
|
||||||
|
.build()]))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(filter: Vec<Filter>) -> Self {
|
pub fn new(filter: Vec<Filter>) -> Self {
|
||||||
let subscription: Option<Subscription> = None;
|
let subscription: Option<Subscription> = None;
|
||||||
let notes = TimelineTab::new(ViewFilter::Notes);
|
let notes = TimelineTab::new(ViewFilter::Notes);
|
||||||
|
|||||||
Reference in New Issue
Block a user