diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs index 29bf7ee..fc7e946 100644 --- a/crates/notedeck_chrome/src/chrome.rs +++ b/crates/notedeck_chrome/src/chrome.rs @@ -471,6 +471,7 @@ fn chrome_handle_app_action( let m_action = notedeck_columns::actionbar::execute_and_process_note_action( note_action, ctx.ndb, + &mut columns.subscriptions, cols, 0, &mut columns.timeline_cache, @@ -527,6 +528,7 @@ fn columns_route_to_profile( let m_action = notedeck_columns::actionbar::execute_and_process_note_action( notedeck::NoteAction::Profile(*pk), ctx.ndb, + &mut columns.subscriptions, cols, 0, &mut columns.timeline_cache, diff --git a/crates/notedeck_columns/src/actionbar.rs b/crates/notedeck_columns/src/actionbar.rs index a2bd5b1..891ec99 100644 --- a/crates/notedeck_columns/src/actionbar.rs +++ b/crates/notedeck_columns/src/actionbar.rs @@ -48,6 +48,7 @@ struct NoteActionResponse { fn execute_note_action( action: NoteAction, ndb: &mut Ndb, + subs: &mut crate::subscriptions::Subscriptions, timeline_cache: &mut TimelineCache, threads: &mut Threads, note_cache: &mut NoteCache, @@ -97,7 +98,7 @@ fn execute_note_action( let kind = TimelineKind::Profile(pubkey); router_action = Some(RouterAction::route_to(Route::Timeline(kind.clone()))); timeline_res = timeline_cache - .open(ndb, note_cache, txn, pool, &kind) + .open(subs, ndb, note_cache, txn, pool, &kind) .map(NotesOpenResult::Timeline); } NoteAction::Note { @@ -134,7 +135,7 @@ fn execute_note_action( let kind = TimelineKind::Hashtag(vec![htag.clone()]); router_action = Some(RouterAction::route_to(Route::Timeline(kind.clone()))); timeline_res = timeline_cache - .open(ndb, note_cache, txn, pool, &kind) + .open(subs, ndb, note_cache, txn, pool, &kind) .map(NotesOpenResult::Timeline); } NoteAction::Repost(note_id) => { @@ -222,6 +223,7 @@ fn execute_note_action( pub fn execute_and_process_note_action( action: NoteAction, ndb: &mut Ndb, + subs: &mut crate::subscriptions::Subscriptions, columns: &mut Columns, col: usize, timeline_cache: &mut TimelineCache, @@ -250,6 +252,7 @@ pub fn execute_and_process_note_action( let resp = execute_note_action( action, ndb, + subs, timeline_cache, threads, note_cache, diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs index dac9122..de44865 100644 --- a/crates/notedeck_columns/src/app.rs +++ b/crates/notedeck_columns/src/app.rs @@ -152,6 +152,7 @@ fn try_process_event( for (kind, timeline) in &mut damus.timeline_cache { let is_ready = timeline::is_timeline_ready( + &mut damus.subscriptions, app_ctx.ndb, app_ctx.pool, app_ctx.note_cache, @@ -469,6 +470,7 @@ impl Damus { parsed_args.is_flag_set(ColumnsFlag::SinceOptimize), ); + let mut subscriptions = Subscriptions::default(); let decks_cache = if tmp_columns { info!("DecksCache: loading from command line arguments"); let mut columns: Columns = Columns::new(); @@ -476,6 +478,7 @@ impl Damus { for col in &parsed_args.columns { let timeline_kind = col.clone().into_timeline_kind(); if let Some(add_result) = columns.add_new_timeline_column( + &mut subscriptions, &mut timeline_cache, &txn, app_context.ndb, @@ -507,7 +510,7 @@ impl Damus { decks_cache } else { info!("DecksCache: creating new with demo configuration"); - DecksCache::new_with_demo_config(&mut timeline_cache, app_context) + DecksCache::new_with_demo_config(&mut subscriptions, &mut timeline_cache, app_context) //for (pk, _) in &app_context.accounts.cache { // cache.add_deck_default(*pk); //} @@ -519,7 +522,7 @@ impl Damus { let threads = Threads::default(); Self { - subscriptions: Subscriptions::default(), + subscriptions, timeline_cache, drafts: Drafts::default(), state: DamusState::Initializing, diff --git a/crates/notedeck_columns/src/column.rs b/crates/notedeck_columns/src/column.rs index dfb7a91..4c4dc9c 100644 --- a/crates/notedeck_columns/src/column.rs +++ b/crates/notedeck_columns/src/column.rs @@ -103,6 +103,7 @@ impl Columns { pub fn add_new_timeline_column( &mut self, + subs: &mut crate::subscriptions::Subscriptions, timeline_cache: &mut TimelineCache, txn: &Transaction, ndb: &Ndb, @@ -112,7 +113,7 @@ impl Columns { ) -> Option { self.columns .push(Column::new(vec![Route::timeline(kind.to_owned())])); - timeline_cache.open(ndb, note_cache, txn, pool, kind) + timeline_cache.open(subs, ndb, note_cache, txn, pool, kind) } pub fn new_column_picker(&mut self) { diff --git a/crates/notedeck_columns/src/decks.rs b/crates/notedeck_columns/src/decks.rs index fc48a0b..470baab 100644 --- a/crates/notedeck_columns/src/decks.rs +++ b/crates/notedeck_columns/src/decks.rs @@ -80,12 +80,12 @@ impl DecksCache { } } - pub fn new_with_demo_config(timeline_cache: &mut TimelineCache, ctx: &mut AppContext) -> Self { + pub fn new_with_demo_config(subs: &mut crate::subscriptions::Subscriptions, timeline_cache: &mut TimelineCache, ctx: &mut AppContext) -> Self { let mut account_to_decks: HashMap = Default::default(); let fallback_pubkey = FALLBACK_PUBKEY(); account_to_decks.insert( fallback_pubkey, - demo_decks(fallback_pubkey, timeline_cache, ctx), + demo_decks(fallback_pubkey, subs, timeline_cache, ctx), ); DecksCache::new(account_to_decks, ctx.i18n) } @@ -117,6 +117,7 @@ impl DecksCache { pub fn add_deck_default( &mut self, ctx: &mut AppContext, + subs: &mut crate::subscriptions::Subscriptions, timeline_cache: &mut TimelineCache, pubkey: Pubkey, ) { @@ -125,6 +126,7 @@ impl DecksCache { // add home and notifications for new accounts add_demo_columns( ctx, + subs, timeline_cache, pubkey, &mut decks.decks_mut()[0].columns, @@ -444,6 +446,7 @@ impl Deck { pub fn add_demo_columns( ctx: &mut AppContext, + subs: &mut crate::subscriptions::Subscriptions, timeline_cache: &mut TimelineCache, pubkey: Pubkey, columns: &mut Columns, @@ -457,6 +460,7 @@ pub fn add_demo_columns( for kind in &timeline_kinds { if let Some(results) = columns.add_new_timeline_column( + subs, timeline_cache, &txn, ctx.ndb, @@ -477,13 +481,14 @@ pub fn add_demo_columns( pub fn demo_decks( demo_pubkey: Pubkey, + subs: &mut crate::subscriptions::Subscriptions, timeline_cache: &mut TimelineCache, ctx: &mut AppContext, ) -> Decks { let deck = { let mut columns = Columns::default(); - add_demo_columns(ctx, timeline_cache, demo_pubkey, &mut columns); + add_demo_columns(ctx, subs, timeline_cache, demo_pubkey, &mut columns); //columns.add_new_timeline_column(Timeline::hashtag("introductions".to_string())); diff --git a/crates/notedeck_columns/src/multi_subscriber.rs b/crates/notedeck_columns/src/multi_subscriber.rs index 567052c..c100263 100644 --- a/crates/notedeck_columns/src/multi_subscriber.rs +++ b/crates/notedeck_columns/src/multi_subscriber.rs @@ -5,7 +5,7 @@ use nostrdb::{Ndb, Subscription}; use notedeck::{filter::HybridFilter, UnifiedSubscription}; use uuid::Uuid; -use crate::{subscriptions, timeline::ThreadSelection}; +use crate::{subscriptions::{self, SubKind, Subscriptions}, timeline::{ThreadSelection, TimelineKind}}; type RootNoteId = NoteId; @@ -383,15 +383,17 @@ impl TimelineSub { ); } - pub fn try_add_remote(&mut self, pool: &mut RelayPool, filter: &HybridFilter) { - self.try_add_remote_with_relay(pool, filter, None); + pub fn try_add_remote(&mut self, subs: &mut Subscriptions, pool: &mut RelayPool, filter: &HybridFilter, timeline_kind: &TimelineKind) { + self.try_add_remote_with_relay(subs, pool, filter, None, timeline_kind); } pub fn try_add_remote_with_relay( &mut self, + subs: &mut Subscriptions, pool: &mut RelayPool, filter: &HybridFilter, relay_url: Option<&str>, + timeline_kind: &TimelineKind, ) { let before = self.state.clone(); match &mut self.state { @@ -402,6 +404,7 @@ impl TimelineSub { } else { pool.subscribe(subid.clone(), filter.remote().to_vec()); } + subs.subs.insert(subid.clone(), SubKind::Timeline(timeline_kind.clone())); self.filter = Some(filter.to_owned()); self.state = SubState::RemoteOnly { remote: subid, @@ -415,6 +418,7 @@ impl TimelineSub { } else { pool.subscribe(subid.clone(), filter.remote().to_vec()); } + subs.subs.insert(subid.clone(), SubKind::Timeline(timeline_kind.clone())); self.filter = Some(filter.to_owned()); self.state = SubState::Unified { unified: UnifiedSubscription { diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs index 558f664..a205e05 100644 --- a/crates/notedeck_columns/src/nav.rs +++ b/crates/notedeck_columns/src/nav.rs @@ -113,7 +113,7 @@ impl SwitchingAction { } if switch_action.switching_to_new { - decks_cache.add_deck_default(ctx, timeline_cache, switch_action.switch_to); + decks_cache.add_deck_default(ctx, subs, timeline_cache, switch_action.switch_to); } // pop nav after switch @@ -487,6 +487,7 @@ fn process_render_nav_action( crate::actionbar::execute_and_process_note_action( note_action, ctx.ndb, + &mut app.subscriptions, get_active_columns_mut(ctx.i18n, ctx.accounts, &mut app.decks_cache), col, &mut app.timeline_cache, diff --git a/crates/notedeck_columns/src/timeline/cache.rs b/crates/notedeck_columns/src/timeline/cache.rs index cf20e06..e212727 100644 --- a/crates/notedeck_columns/src/timeline/cache.rs +++ b/crates/notedeck_columns/src/timeline/cache.rs @@ -175,6 +175,7 @@ impl TimelineCache { /// subscription pub fn open( &mut self, + subs: &mut crate::subscriptions::Subscriptions, ndb: &Ndb, note_cache: &mut NoteCache, txn: &Transaction, @@ -224,10 +225,10 @@ impl TimelineCache { // Check if this is a relay-specific timeline match &timeline.kind { TimelineKind::Relay(relay_url, _) => { - timeline.subscription.try_add_remote_with_relay(pool, filter, Some(relay_url)); + timeline.subscription.try_add_remote_with_relay(subs, pool, filter, Some(relay_url), &timeline.kind); } _ => { - timeline.subscription.try_add_remote(pool, filter); + timeline.subscription.try_add_remote(subs, pool, filter, &timeline.kind); } } } else { diff --git a/crates/notedeck_columns/src/timeline/kind.rs b/crates/notedeck_columns/src/timeline/kind.rs index 2a4496f..6bfa2dd 100644 --- a/crates/notedeck_columns/src/timeline/kind.rs +++ b/crates/notedeck_columns/src/timeline/kind.rs @@ -371,7 +371,8 @@ impl TimelineKind { } TimelineKind::Relay(relay_url, hashtags) => { writer.write_token("relay"); - writer.write_token(relay_url); + // URL-encode the relay URL to avoid issues with the ":" delimiter + writer.write_token(&urlencoding::encode(relay_url)); if let Some(ht) = hashtags { writer.write_token(&ht.join(" ")); } else { @@ -445,7 +446,12 @@ impl TimelineKind { }, |p| { p.parse_token("relay")?; - let relay_url = p.pull_token()?.to_string(); + let encoded_relay_url = p.pull_token()?; + // URL-decode the relay URL + let relay_url = urlencoding::decode(encoded_relay_url) + .map(|s| s.to_string()) + .unwrap_or_else(|_| encoded_relay_url.to_string()); + let hashtags_str = p.pull_token()?; let hashtags = if hashtags_str.is_empty() { None diff --git a/crates/notedeck_columns/src/timeline/mod.rs b/crates/notedeck_columns/src/timeline/mod.rs index ca7e72c..90eec7d 100644 --- a/crates/notedeck_columns/src/timeline/mod.rs +++ b/crates/notedeck_columns/src/timeline/mod.rs @@ -562,7 +562,7 @@ pub fn setup_new_timeline( unknown_ids: &mut UnknownIds, ) { // if we're ready, setup local subs - if is_timeline_ready(ndb, pool, note_cache, timeline, accounts, unknown_ids) { + if is_timeline_ready(subs, ndb, pool, note_cache, timeline, accounts, unknown_ids) { if let Err(err) = setup_timeline_nostrdb_sub(ndb, txn, note_cache, timeline, unknown_ids) { error!("setup_new_timeline: {err}"); } @@ -783,6 +783,7 @@ fn setup_timeline_nostrdb_sub( /// example, when we have to fetch a contact list before we do the actual /// following list query. pub fn is_timeline_ready( + subs: &mut crate::subscriptions::Subscriptions, ndb: &Ndb, pool: &mut RelayPool, note_cache: &mut NoteCache, @@ -870,7 +871,7 @@ pub fn is_timeline_ready( //let ck = &timeline.kind; //let subid = damus.gen_subid(&SubKind::Column(ck.clone())); - timeline.subscription.try_add_remote(pool, &filter); + timeline.subscription.try_add_remote(subs, pool, &filter, &timeline.kind); true } }