Replace relay subscriptions with cache-backed discovery sync
This commit is contained in:
@@ -4,12 +4,12 @@ use std::rc::Rc;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
||||
IntoElement, ParentElement, Render, ScrollStrategy, SharedString, Styled, Subscription,
|
||||
IntoElement, ParentElement, Render, ScrollStrategy, SharedString, Styled, Subscription, Task,
|
||||
WeakEntity, Window, div, px, relative, size,
|
||||
};
|
||||
use gpui_base::{VirtualListScrollHandle, v_virtual_list};
|
||||
use nip29::{Discovery, GroupCandidate, GroupKey, GroupsEvent, GroupsRegistry};
|
||||
use nostr_sdk::prelude::RelayUrl;
|
||||
use nostr_sdk::prelude::{RelayUrl, Timestamp};
|
||||
use settings::AppSettings;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use theme::ActiveTheme;
|
||||
@@ -40,19 +40,21 @@ pub struct BrowsePanel {
|
||||
/// The groups the relay has announced so far
|
||||
candidates: Vec<GroupCandidate>,
|
||||
/// The groups discovered from the cache and the relays
|
||||
discovery: Entity<Discovery>,
|
||||
discovery: Discovery,
|
||||
/// Whether the discovery sync is still running
|
||||
discovering: bool,
|
||||
/// The scroll position of the group list
|
||||
scroll_handle: VirtualListScrollHandle,
|
||||
/// Whether the relay is still answering
|
||||
loading: bool,
|
||||
_subscriptions: SmallVec<[Subscription; 3]>,
|
||||
tasks: SmallVec<[Task<()>; 2]>,
|
||||
_subscriptions: SmallVec<[Subscription; 2]>,
|
||||
}
|
||||
|
||||
impl BrowsePanel {
|
||||
fn new(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let input = cx.new(|cx| InputState::new(window, cx).placeholder(INPUT_PLACEHOLDER));
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
let discovery = registry.read(cx).discovery();
|
||||
|
||||
let mut subscriptions = smallvec![];
|
||||
|
||||
@@ -64,10 +66,6 @@ impl BrowsePanel {
|
||||
}),
|
||||
);
|
||||
|
||||
subscriptions.push(cx.observe(&discovery, |_, _, cx| {
|
||||
cx.notify();
|
||||
}));
|
||||
|
||||
subscriptions.push(
|
||||
cx.subscribe(®istry, |this, _registry, event, cx| match event {
|
||||
GroupsEvent::Browsed(candidate) => {
|
||||
@@ -76,15 +74,23 @@ impl BrowsePanel {
|
||||
GroupsEvent::BrowseSettled(relay) => {
|
||||
this.settle(relay.clone(), cx);
|
||||
}
|
||||
GroupsEvent::Synced => {
|
||||
this.refresh_discovery(cx);
|
||||
}
|
||||
GroupsEvent::Members {
|
||||
key,
|
||||
created_at,
|
||||
members,
|
||||
} => {
|
||||
this.push_members(key.clone(), *created_at, *members, cx);
|
||||
}
|
||||
_ => {}
|
||||
}),
|
||||
);
|
||||
|
||||
// Wait for the panel to leave the stack before kicking off the sweep.
|
||||
cx.defer_in(window, |_this, _window, cx| {
|
||||
GroupsRegistry::global(cx).update(cx, |registry, cx| {
|
||||
registry.discover(cx);
|
||||
});
|
||||
cx.defer_in(window, |this, _window, cx| {
|
||||
this.load_cached(cx);
|
||||
this.sync_discovery(cx);
|
||||
});
|
||||
|
||||
Self {
|
||||
@@ -93,13 +99,77 @@ impl BrowsePanel {
|
||||
input,
|
||||
relay: None,
|
||||
candidates: Vec::new(),
|
||||
discovery,
|
||||
discovery: Discovery::default(),
|
||||
discovering: true,
|
||||
scroll_handle: VirtualListScrollHandle::new(),
|
||||
loading: false,
|
||||
tasks: smallvec![],
|
||||
_subscriptions: subscriptions,
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the groups from the local database.
|
||||
fn load_cached(&mut self, cx: &mut Context<Self>) {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
let discovery = registry.read(cx).cached_discovery(cx);
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
let discovery = discovery.await;
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.discovery = discovery;
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
|
||||
/// Sync the discoverable groups with the relays.
|
||||
fn sync_discovery(&mut self, cx: &mut Context<Self>) {
|
||||
self.discovering = true;
|
||||
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
let sync = registry.read(cx).discover(cx);
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
sync.await;
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.discovering = false;
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
|
||||
/// A browsed group announced its member list.
|
||||
fn push_members(
|
||||
&mut self,
|
||||
key: GroupKey,
|
||||
created_at: Timestamp,
|
||||
members: usize,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.discovery.set_members(key, created_at, members);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// The discovery synced new groups: re-query the local database.
|
||||
fn refresh_discovery(&mut self, cx: &mut Context<Self>) {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
let discovery = registry.read(cx).cached_discovery(cx);
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
let discovery = discovery.await;
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.discovery = discovery;
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}));
|
||||
}
|
||||
|
||||
/// Browse the relay in the input.
|
||||
fn browse(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
@@ -189,7 +259,6 @@ impl BrowsePanel {
|
||||
|
||||
let cards: Vec<GroupCandidate> = self
|
||||
.discovery
|
||||
.read(cx)
|
||||
.discovered()
|
||||
.iter()
|
||||
.filter(|candidate| !joined.contains(&candidate.key))
|
||||
@@ -242,7 +311,7 @@ impl BrowsePanel {
|
||||
fn render_card(&self, candidate: &GroupCandidate, cx: &mut Context<Self>) -> AnyElement {
|
||||
let key = candidate.key.clone();
|
||||
let seed = key.cache_tag();
|
||||
let members = self.discovery.read(cx).members(&key).unwrap_or(0);
|
||||
let members = self.discovery.members(&key).unwrap_or(0);
|
||||
|
||||
let name = SharedString::from(candidate.display_name().to_owned());
|
||||
let relay = SharedString::from(key.relay().as_str().to_owned());
|
||||
@@ -346,11 +415,11 @@ impl BrowsePanel {
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_1p5()
|
||||
.child(Icon::new(IconName::Group))
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(Icon::new(IconName::Book))
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from(format!("{members} members"))),
|
||||
),
|
||||
),
|
||||
@@ -392,8 +461,6 @@ impl Render for BrowsePanel {
|
||||
|
||||
let (discovered_count, discovering) = if discover {
|
||||
let registry = GroupsRegistry::global(cx);
|
||||
let discovery = self.discovery.read(cx);
|
||||
let discovering = discovery.loading();
|
||||
|
||||
let joined: Vec<GroupKey> = registry
|
||||
.read(cx)
|
||||
@@ -402,13 +469,14 @@ impl Render for BrowsePanel {
|
||||
.map(|group| group.read(cx).key().clone())
|
||||
.collect();
|
||||
|
||||
let discovered_count = discovery
|
||||
let discovered_count = self
|
||||
.discovery
|
||||
.discovered()
|
||||
.iter()
|
||||
.filter(|candidate| !joined.contains(&candidate.key))
|
||||
.count();
|
||||
|
||||
(discovered_count, discovering)
|
||||
(discovered_count, self.discovering)
|
||||
} else {
|
||||
(0, false)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user