mirror of
https://github.com/damus-io/notedeck.git
synced 2024-09-18 21:03:31 +00:00
remove duplicate filter types
only use nostrdb::Filter Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
8c458f8f78
commit
9328ef2dff
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -1114,8 +1114,8 @@ dependencies = [
|
||||
"env_logger 0.11.3",
|
||||
"ewebsock",
|
||||
"hex",
|
||||
"log",
|
||||
"nostr",
|
||||
"nostrdb",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@ -2296,7 +2296,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostrdb"
|
||||
version = "0.3.4"
|
||||
source = "git+https://github.com/damus-io/nostrdb-rs?rev=04e5917b44b0112ecfd0eb93e8a1e2c81fce1d75#04e5917b44b0112ecfd0eb93e8a1e2c81fce1d75"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
@ -2343,6 +2342,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tracing-wasm",
|
||||
"uuid",
|
||||
"wasm-bindgen-futures",
|
||||
"winit",
|
||||
]
|
||||
@ -4237,6 +4237,15 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -11,6 +11,11 @@ default-run = "notedeck"
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
|
||||
[workspace.dependencies]
|
||||
#nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "04e5917b44b0112ecfd0eb93e8a1e2c81fce1d75" }
|
||||
nostrdb = { path = "/Users/jb55/dev/github/damus-io/nostrdb-rs" }
|
||||
#nostrdb = "0.3.4"
|
||||
|
||||
[dependencies]
|
||||
#egui-android = { git = "https://github.com/jb55/egui-android.git" }
|
||||
egui = { git = "https://github.com/emilk/egui", rev = "fcb7764e48ce00f8f8e58da10f937410d65b0bfb" }
|
||||
@ -33,14 +38,13 @@ serde_json = "1.0.89"
|
||||
env_logger = "0.10.0"
|
||||
puffin_egui = { version = "0.27.0", optional = true }
|
||||
puffin = { version = "0.19.0", optional = true }
|
||||
nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "04e5917b44b0112ecfd0eb93e8a1e2c81fce1d75" }
|
||||
#nostrdb = { path = "/Users/jb55/dev/github/damus-io/nostrdb-rs" }
|
||||
#nostrdb = "0.3.4"
|
||||
hex = "0.4.3"
|
||||
base32 = "0.4.0"
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
bitflags = "2.5.0"
|
||||
uuid = { version = "1.10.0", features = ["v4"] }
|
||||
nostrdb = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
security-framework = "2.11.0"
|
||||
|
@ -10,8 +10,8 @@ ewebsock = { version = "0.2.0", features = ["tls"] }
|
||||
serde_derive = "1"
|
||||
serde = { version = "1", features = ["derive"] } # You only need this if you want app persistence
|
||||
serde_json = "1.0.89"
|
||||
tracing = "0.1.37"
|
||||
nostrdb = { workspace = true }
|
||||
nostr = { version = "0.30.0" }
|
||||
hex = "0.4.3"
|
||||
log = "0.4.20"
|
||||
tracing = "0.1.40"
|
||||
env_logger = "0.11.1"
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::{Filter, Note};
|
||||
use crate::{Error, Note};
|
||||
use nostrdb::Filter;
|
||||
use serde_json::json;
|
||||
|
||||
/// Messages sent by clients, received by relays
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Debug)]
|
||||
pub enum ClientMessage {
|
||||
Event {
|
||||
note: Note,
|
||||
@ -34,23 +35,25 @@ impl ClientMessage {
|
||||
ClientMessage::Close { sub_id }
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> String {
|
||||
match self {
|
||||
pub fn to_json(&self) -> Result<String, Error> {
|
||||
Ok(match self {
|
||||
Self::Event { note } => json!(["EVENT", note]).to_string(),
|
||||
Self::Raw(raw) => raw.clone(),
|
||||
Self::Req { sub_id, filters } => {
|
||||
let mut json = json!(["REQ", sub_id]);
|
||||
let mut filters = json!(filters);
|
||||
|
||||
if let Some(json) = json.as_array_mut() {
|
||||
if let Some(filters) = filters.as_array_mut() {
|
||||
json.append(filters);
|
||||
if filters.is_empty() {
|
||||
format!("[\"REQ\",\"{}\",{{ }}]", sub_id)
|
||||
} else if filters.len() == 1 {
|
||||
let filters_json_str = filters[0].json()?;
|
||||
format!("[\"REQ\",\"{}\",{}]", sub_id, filters_json_str)
|
||||
} else {
|
||||
let filters_json_str: Result<Vec<String>, Error> = filters
|
||||
.into_iter()
|
||||
.map(|f| f.json().map_err(Into::<Error>::into))
|
||||
.collect();
|
||||
format!("[\"REQ\",\"{}\",{}]", sub_id, filters_json_str?.join(","))
|
||||
}
|
||||
}
|
||||
|
||||
json.to_string()
|
||||
}
|
||||
Self::Close { sub_id } => json!(["CLOSE", sub_id]).to_string(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub enum Error {
|
||||
InvalidPublicKey,
|
||||
// Secp(secp256k1::Error),
|
||||
Json(serde_json::Error),
|
||||
Nostrdb(nostrdb::Error),
|
||||
Generic(String),
|
||||
}
|
||||
|
||||
@ -29,6 +30,7 @@ impl std::cmp::PartialEq for Error {
|
||||
// This is slightly wrong but whatevs
|
||||
(Error::Json(..), Error::Json(..)) => true,
|
||||
(Error::Generic(left), Error::Generic(right)) => left == right,
|
||||
(Error::Nostrdb(left), Error::Nostrdb(right)) => left == right,
|
||||
//(Error::Secp(left), Error::Secp(right)) => left == right,
|
||||
_ => false,
|
||||
}
|
||||
@ -47,6 +49,7 @@ impl fmt::Display for Error {
|
||||
Self::InvalidPublicKey => write!(f, "invalid public key"),
|
||||
//Self::Secp(e) => write!(f, "{e}"),
|
||||
Self::Json(e) => write!(f, "{e}"),
|
||||
Self::Nostrdb(e) => write!(f, "{e}"),
|
||||
Self::Generic(e) => write!(f, "{e}"),
|
||||
}
|
||||
}
|
||||
@ -85,3 +88,9 @@ impl From<serde_json::Error> for Error {
|
||||
Error::Json(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nostrdb::Error> for Error {
|
||||
fn from(e: nostrdb::Error) -> Self {
|
||||
Error::Nostrdb(e)
|
||||
}
|
||||
}
|
||||
|
@ -1,91 +1 @@
|
||||
use crate::{NoteId, Pubkey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
|
||||
pub struct Filter {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ids: Option<Vec<NoteId>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub authors: Option<Vec<Pubkey>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kinds: Option<Vec<u64>>,
|
||||
#[serde(rename = "#e")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub events: Option<Vec<NoteId>>,
|
||||
#[serde(rename = "#p")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub pubkeys: Option<Vec<Pubkey>>,
|
||||
#[serde(rename = "#t")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hashtags: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub since: Option<u64>, // unix timestamp seconds
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub until: Option<u64>, // unix timestamp seconds
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub limit: Option<u16>,
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn new() -> Filter {
|
||||
Filter {
|
||||
ids: None,
|
||||
authors: None,
|
||||
kinds: None,
|
||||
events: None,
|
||||
pubkeys: None,
|
||||
hashtags: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_limit() -> u16 {
|
||||
250
|
||||
}
|
||||
|
||||
pub fn default_remote_limit() -> u16 {
|
||||
150
|
||||
}
|
||||
|
||||
pub fn ids(mut self, ids: Vec<NoteId>) -> Self {
|
||||
self.ids = Some(ids);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn authors(mut self, authors: Vec<Pubkey>) -> Self {
|
||||
self.authors = Some(authors);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kinds(mut self, kinds: Vec<u64>) -> Self {
|
||||
self.kinds = Some(kinds);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn events(mut self, events: Vec<NoteId>) -> Self {
|
||||
self.events = Some(events);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn pubkeys(mut self, pubkeys: Vec<Pubkey>) -> Self {
|
||||
self.pubkeys = Some(pubkeys);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn since(mut self, since: u64) -> Self {
|
||||
self.since = Some(since);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn until(mut self, until: u64) -> Self {
|
||||
self.until = Some(until);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn limit(mut self, limit: u16) -> Self {
|
||||
self.limit = Some(limit);
|
||||
self
|
||||
}
|
||||
}
|
||||
pub type Filter = nostrdb::Filter;
|
||||
|
@ -1,9 +1,9 @@
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::Error;
|
||||
use log::debug;
|
||||
use nostr::bech32::Hrp;
|
||||
use std::fmt;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
pub struct Pubkey([u8; 32]);
|
||||
|
@ -161,7 +161,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_handle_valid_event() -> Result<()> {
|
||||
use log::debug;
|
||||
use tracing::debug;
|
||||
|
||||
env_logger::init();
|
||||
let valid_event_msg = r#"["EVENT", "random_string", {"id":"70b10f70c1318967eddf12527799411b1a9780ad9c43858f5e5fcd45486a13a5","pubkey":"379e863e8357163b5bce5d2688dc4f1dcc2d505222fb8d74db600f30535dfdfe","created_at":1612809991,"kind":1,"tags":[],"content":"test","sig":"273a9cd5d11455590f4359500bccb7a89428262b96b3ea87a756b770964472f8c3e87f5d5e64d8d2e859a71462a3f477b554565c4f2f326cb01dd7620db71502"}]"#;
|
||||
|
@ -1,9 +1,10 @@
|
||||
use ewebsock::{WsMessage, WsReceiver, WsSender};
|
||||
|
||||
use crate::{ClientMessage, Filter, Result};
|
||||
use log::info;
|
||||
use crate::{ClientMessage, Result};
|
||||
use nostrdb::Filter;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
pub mod message;
|
||||
pub mod pool;
|
||||
@ -60,7 +61,18 @@ impl Relay {
|
||||
}
|
||||
|
||||
pub fn send(&mut self, msg: &ClientMessage) {
|
||||
let txt = WsMessage::Text(msg.to_json());
|
||||
let json = match msg.to_json() {
|
||||
Ok(json) => {
|
||||
debug!("sending {} to {}", json, self.url);
|
||||
json
|
||||
}
|
||||
Err(e) => {
|
||||
error!("error serializing json for filter: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let txt = WsMessage::Text(json);
|
||||
self.sender.send(txt);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::relay::{Relay, RelayStatus};
|
||||
use crate::{ClientMessage, Result};
|
||||
use nostrdb::Filter;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@ -71,6 +72,12 @@ impl RelayPool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subscribe(&mut self, subid: String, filter: Vec<Filter>) {
|
||||
for relay in &mut self.relays {
|
||||
relay.relay.subscribe(subid.clone(), filter.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep relay connectiongs alive by pinging relays that haven't been
|
||||
/// pinged in awhile. Adjust ping rate with [`ping_rate`].
|
||||
pub fn keepalive_ping(&mut self, wakeup: impl Fn() + Send + Sync + Clone + 'static) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
[{"limit": 1000,
|
||||
{"limit": 1000,
|
||||
"kinds": [
|
||||
1
|
||||
],
|
||||
@ -39,4 +39,4 @@
|
||||
"womeninnostr",
|
||||
"osrs"
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
[{"limit": 500, "kinds":[1], "#p": ["32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"]}]
|
||||
{"limit": 500, "kinds":[1], "#p": ["32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"]}
|
||||
|
File diff suppressed because one or more lines are too long
@ -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(¬es);
|
||||
(thread, br)
|
||||
// thread.view.insert(¬es); <-- 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)
|
||||
),
|
||||
|
72
src/app.rs
72
src/app.rs
@ -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());
|
||||
|
@ -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());
|
||||
pub fn default_limit() -> u64 {
|
||||
250
|
||||
}
|
||||
|
||||
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_remote_limit() -> u64 {
|
||||
150
|
||||
}
|
||||
|
@ -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),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user