clean up nip29 logging and rework browse panel header

This commit is contained in:
2026-10-07 15:19:02 +07:00
parent e472077941
commit 586fea796d
2 changed files with 79 additions and 100 deletions
+61 -78
View File
@@ -90,7 +90,6 @@ fn is_own_subscription(id: &SubscriptionId) -> bool {
|| id.starts_with(PAGE_PREFIX)
}
/// The group id, member count and timestamp of a group members event.
fn parse_members(event: &Event) -> Option<(GroupId, Timestamp, usize)> {
if event.kind != Kind::GroupMembers {
return None;
@@ -102,8 +101,6 @@ fn parse_members(event: &Event) -> Option<(GroupId, Timestamp, usize)> {
Some((id, event.created_at, members))
}
/// Reconcile a filter with the relays via negentropy, returning the events
/// that were downloaded to the local database.
async fn reconcile(
client: &Client,
filter: Filter,
@@ -112,22 +109,19 @@ async fn reconcile(
let output = match client.sync(filter).with(urls).await {
Ok(output) => output,
Err(error) => {
log::warn!("nip29: the reconciliation failed: {error}");
log::warn!("the reconciliation failed: {error}");
return HashMap::new();
}
};
for (relay, error) in &output.failed {
log::debug!("nip29: syncing with {relay} failed: {error}");
log::debug!("syncing with {relay} failed: {error}");
}
output.value.received
}
/// Pair the downloaded events with the relay that served them.
///
/// The database does not keep relay associations, so the pairing has to
/// happen while the reconciliation still knows them.
async fn pull_received(
client: &Client,
received: HashMap<EventId, HashSet<RelayUrl>>,
@@ -202,16 +196,15 @@ impl GroupsRegistry {
}));
cx.defer(move |cx| {
if let Err(error) = this.update(cx, |this, cx| {
this.update(cx, |this, cx| {
this.handle_notifications(cx);
this.load_cached(cx);
if nostr.read(cx).current_user().is_some() {
this.load(cx);
}
}) {
log::warn!("nip29: initializing the registry failed: {error}");
}
})
.ok();
});
Self {
@@ -278,7 +271,7 @@ impl GroupsRegistry {
});
}
}) {
log::warn!("nip29: marking the refused join failed: {error}");
log::warn!("marking the refused join failed: {error}");
}
}
}));
@@ -337,11 +330,11 @@ impl GroupsRegistry {
.close_on(opts)
.await
{
log::warn!("nip29: browsing {relay} failed: {error}");
log::warn!("browsing {relay} failed: {error}");
}
if let Err(error) = tx.send_async(Signal::BrowseSettled(id)).await {
log::warn!("nip29: the browse settle signal was dropped: {error}");
log::warn!("the browse settle signal was dropped: {error}");
}
}));
}
@@ -405,7 +398,7 @@ impl GroupsRegistry {
let (authors, lists) = match task.await {
Ok(ok) => ok,
Err(error) => {
log::warn!("nip29: loading the cached groups failed: {error}");
log::warn!("loading the cached groups failed: {error}");
(HashSet::new(), Vec::new())
}
};
@@ -413,21 +406,20 @@ impl GroupsRegistry {
if let Err(error) = this.update(cx, |this, cx| {
this.absorb_lists(lists, cx);
}) {
log::warn!("nip29: applying the cached group lists failed: {error}");
log::warn!("applying the cached group lists failed: {error}");
return;
}
// Show the cached metadata before the relays answer.
let previews = match this.update(cx, |this, cx| this.load_cached_previews(cx)) {
Ok(task) => match task.await {
Ok(previews) => previews,
Err(error) => {
log::warn!("nip29: loading the cached group metadata failed: {error}");
log::warn!("loading the cached group metadata failed: {error}");
Vec::new()
}
},
Err(error) => {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
return;
}
};
@@ -437,12 +429,12 @@ impl GroupsRegistry {
Ok(task) => match task.await {
Ok(members) => members,
Err(error) => {
log::warn!("nip29: loading the cached group members failed: {error}");
log::warn!("loading the cached group members failed: {error}");
Vec::new()
}
},
Err(error) => {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
return;
}
};
@@ -451,16 +443,14 @@ impl GroupsRegistry {
this.absorb_cached_previews(previews, cx);
this.absorb_cached_members(members, cx);
}) {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
return;
}
// Reconcile the contacts' group lists with the pool relays: only
// the events missing locally are downloaded and stored.
let lists = match this.update(cx, |this, cx| this.sync_lists(authors, cx)) {
Ok(task) => task,
Err(error) => {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
return;
}
};
@@ -469,7 +459,7 @@ impl GroupsRegistry {
let sweep = match this.update(cx, |this, cx| this.sync_sweep(cx)) {
Ok(task) => task,
Err(error) => {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
return;
}
};
@@ -477,7 +467,7 @@ impl GroupsRegistry {
let lists = match lists.await {
Ok(lists) => lists,
Err(error) => {
log::warn!("nip29: syncing the contacts group lists failed: {error}");
log::warn!("syncing the contacts group lists failed: {error}");
Vec::new()
}
};
@@ -485,13 +475,13 @@ impl GroupsRegistry {
if let Err(error) = this.update(cx, |this, cx| {
this.absorb_lists(lists, cx);
}) {
log::warn!("nip29: applying the contacts group lists failed: {error}");
log::warn!("applying the contacts group lists failed: {error}");
}
let sweep = match sweep.await {
Ok(events) => events,
Err(error) => {
log::warn!("nip29: syncing the discovered groups failed: {error}");
log::warn!("syncing the discovered groups failed: {error}");
Vec::new()
}
};
@@ -501,7 +491,7 @@ impl GroupsRegistry {
this.absorb_discovered(relay, &event, cx);
}
}) {
log::warn!("nip29: applying the discovered groups failed: {error}");
log::warn!("applying the discovered groups failed: {error}");
}
// The previews cover the relays the lists just referenced.
@@ -509,12 +499,12 @@ impl GroupsRegistry {
Ok(task) => match task.await {
Ok(previews) => previews,
Err(error) => {
log::warn!("nip29: syncing the group previews failed: {error}");
log::warn!("syncing the group previews failed: {error}");
Vec::new()
}
},
Err(error) => {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
return;
}
};
@@ -527,7 +517,7 @@ impl GroupsRegistry {
this.discovery
.update(cx, |discovery, cx| discovery.settle(cx));
}) {
log::warn!("nip29: discovering the groups failed: {error}");
log::warn!("discovering the groups failed: {error}");
}
}));
}
@@ -560,7 +550,7 @@ impl GroupsRegistry {
let metadata = match GroupMetadata::parse(&event) {
Ok(metadata) => metadata,
Err(error) => {
log::warn!("nip29: ignoring malformed cached group metadata: {error}");
log::warn!("ignoring malformed cached group metadata: {error}");
return newest;
}
};
@@ -717,7 +707,7 @@ impl GroupsRegistry {
let metadata = match GroupMetadata::parse(event) {
Ok(metadata) => metadata,
Err(error) => {
log::warn!("nip29: ignoring malformed group metadata from {relay}: {error}");
log::warn!("ignoring malformed group metadata from {relay}: {error}");
return;
}
};
@@ -762,7 +752,7 @@ impl GroupsRegistry {
async move {
if let Err(error) = client.add_relay(relay.clone()).and_connect().await {
log::warn!("nip29: connecting to {relay} failed: {error}");
log::warn!("connecting to {relay} failed: {error}");
}
let filter = Filter::new()
@@ -811,10 +801,7 @@ impl GroupsRegistry {
fn absorb_group_list(&mut self, event: &Event, cx: &mut Context<Self>) {
let Ok(list) = GroupList::parse(event) else {
log::warn!(
"nip29: ignoring a malformed group list from {}",
event.pubkey
);
log::warn!("ignoring a malformed group list from {}", event.pubkey);
return;
};
@@ -861,7 +848,7 @@ impl GroupsRegistry {
let metadata = match GroupMetadata::parse(event) {
Ok(metadata) => metadata,
Err(error) => {
log::warn!("nip29: ignoring malformed group metadata from {relay}: {error}");
log::warn!("ignoring malformed group metadata from {relay}: {error}");
return;
}
};
@@ -925,7 +912,7 @@ impl GroupsRegistry {
self.tasks.push(cx.spawn(async move |this, cx| {
if let Err(error) = sent.await {
log::warn!("nip29: leaving {} failed: {error}", key.id());
log::warn!("leaving {} failed: {error}", key.id());
return;
}
this.update(cx, |this, cx| {
@@ -963,7 +950,7 @@ impl GroupsRegistry {
self.tasks.push(cx.background_spawn(async move {
for id in ids {
if let Err(error) = client.unsubscribe(&id).await {
log::warn!("nip29: unsubscribing {id} failed: {error}");
log::warn!("unsubscribing {id} failed: {error}");
}
}
}));
@@ -995,11 +982,14 @@ impl GroupsRegistry {
self.tasks
.push(cx.spawn(async move |this, cx| match task.await {
Ok(list) => {
if let Err(error) = this.update(cx, |this, cx| this.merge(list, cx)) {
log::warn!("nip29: applying the cached group list failed: {error}");
}
this.update(cx, |this, cx| {
this.merge(list, cx);
})
.ok();
}
Err(error) => {
log::warn!("loading the cached group list failed: {error}");
}
Err(error) => log::warn!("nip29: loading the cached group list failed: {error}"),
}));
}
@@ -1008,7 +998,7 @@ impl GroupsRegistry {
let client = nostr.read(cx).client();
let signer = nostr.read(cx).signer();
let updates: Task<Result<(), Error>> = cx.background_spawn(async move {
cx.background_spawn(async move {
let me = signer.get_public_key_async().await?;
let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
let filter = Filter::new().author(me).kind(Kind::SimpleGroups).limit(1);
@@ -1019,14 +1009,9 @@ impl GroupsRegistry {
.close_on(opts)
.await?;
Ok(())
});
self.tasks.push(cx.spawn(async move |_this, _cx| {
if let Err(error) = updates.await {
log::warn!("nip29: subscribing to the group list failed: {error}");
}
}));
Ok::<(), anyhow::Error>(())
})
.detach();
self.watch_forks(cx);
}
@@ -1050,7 +1035,6 @@ impl GroupsRegistry {
self.tasks.push(cx.background_spawn(async move {
loop {
executor.timer(FORK_INTERVAL).await;
if tx.send_async(Signal::Forks).await.is_err() {
break;
}
@@ -1091,14 +1075,14 @@ impl GroupsRegistry {
.with_id(fork_subscription_id())
.await
{
log::warn!("nip29: subscribing to the admins' group lists failed: {error}");
log::warn!("subscribing to the admins' group lists failed: {error}");
}
}));
}
fn absorb_fork_list(&mut self, event: &Event, cx: &mut Context<Self>) {
let Ok(list) = GroupList::parse(event) else {
log::warn!("nip29: ignoring a malformed admin group list");
log::warn!("ignoring a malformed admin group list");
return;
};
@@ -1201,7 +1185,7 @@ impl GroupsRegistry {
self.tasks.push(cx.background_spawn(async move {
for id in [id, page] {
if let Err(error) = client.unsubscribe(&id).await {
log::warn!("nip29: unsubscribing {id} failed: {error}");
log::warn!("unsubscribing {id} failed: {error}");
}
}
@@ -1210,7 +1194,7 @@ impl GroupsRegistry {
.custom_tag(SingleLetterTag::LOWERCASE_R, cache_tag);
if let Err(error) = client.database().delete(filter).await {
log::warn!("nip29: clearing the group cache failed: {error}");
log::warn!("clearing the group cache failed: {error}");
}
}));
@@ -1271,18 +1255,17 @@ impl GroupsRegistry {
let event = match builder.finalize_async(&signer).await {
Ok(event) => event,
Err(error) => {
log::warn!("nip29: signing the group list failed: {error}");
log::warn!("signing the group list failed: {error}");
return;
}
};
match client.send_event(&event).to_nip65().await {
Ok(output) if output.failed.is_empty() => {}
Ok(output) => log::warn!(
"nip29: {} relay(s) rejected the group list",
output.failed.len()
),
Err(error) => log::warn!("nip29: publishing the group list failed: {error}"),
Ok(output) => {
log::warn!("{} relay(s) rejected the group list", output.failed.len())
}
Err(error) => log::warn!("publishing the group list failed: {error}"),
}
}));
}
@@ -1307,7 +1290,7 @@ impl GroupsRegistry {
.read_with(cx, |group, cx| group.save_envelope(event, cx))
.await
{
log::warn!("nip29: caching failed: {error}");
log::warn!("caching failed: {error}");
return;
}
@@ -1318,7 +1301,7 @@ impl GroupsRegistry {
});
}
Err(error) => {
log::warn!("nip29: reloading {} failed: {error}", logged.id());
log::warn!("reloading {} failed: {error}", logged.id());
}
}
}));
@@ -1345,7 +1328,7 @@ impl GroupsRegistry {
});
}
Err(error) => {
log::warn!("nip29: loading {} state failed: {error}", logged.id());
log::warn!("loading {} state failed: {error}", logged.id());
}
}));
}
@@ -1365,7 +1348,7 @@ impl GroupsRegistry {
.read_with(cx, |group, cx| group.save_envelope(event.clone(), cx))
.await
{
log::warn!("nip29: caching failed: {error}");
log::warn!("caching failed: {error}");
return;
}
@@ -1411,7 +1394,7 @@ impl GroupsRegistry {
self.tasks.push(cx.spawn(async move |this, cx| {
if let Err(error) = purge.await {
log::warn!("nip29: dropping the deleted envelope failed: {error}");
log::warn!("dropping the deleted envelope failed: {error}");
}
this.update(cx, |this, cx| {
group.update(cx, |group, cx| {
@@ -1427,7 +1410,7 @@ impl GroupsRegistry {
if id == list_subscription_id() {
match GroupList::parse(&event) {
Ok(list) => self.merge(list, cx),
Err(error) => log::warn!("nip29: ignoring a malformed group list: {error}"),
Err(error) => log::warn!("ignoring a malformed group list: {error}"),
}
return;
}
@@ -1470,7 +1453,7 @@ impl GroupsRegistry {
}
let Ok(metadata) = GroupMetadata::parse(event) else {
log::warn!("nip29: ignoring malformed group metadata from {relay}");
log::warn!("ignoring malformed group metadata from {relay}");
return;
};
@@ -1515,12 +1498,12 @@ impl GroupsRegistry {
fn handle_closed(&mut self, id: SubscriptionId, reason: String, cx: &mut Context<Self>) {
if let Some(relay) = self.browse.get(&id) {
log::warn!("nip29: browsing {relay} was refused: {reason}");
log::warn!("browsing {relay} was refused: {reason}");
return;
}
if id == fork_subscription_id() {
log::debug!("nip29: the admins' group lists were refused: {reason}");
log::debug!("the admins' group lists were refused: {reason}");
return;
}
@@ -1531,7 +1514,7 @@ impl GroupsRegistry {
if is_page(&id) {
self.routes.remove(&id);
log::warn!(
"nip29: loading older messages in {} was refused: {reason}",
"loading older messages in {} was refused: {reason}",
key.id()
);
+18 -22
View File
@@ -16,7 +16,6 @@ use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::dock::{DockArea, DockPlacement, Panel, PanelEvent, PanelHandle};
use ui::indicator::Indicator;
use ui::input::{Input, InputEvent, InputState};
use ui::notification::Notification;
use ui::scroll::Scrollbar;
@@ -214,10 +213,6 @@ impl BrowsePanel {
self.render_card_rows(cards, cx)
}
/// A row holds two group cards side by side.
///
/// The cards are the relative slice of the visible rows, so they pair up
/// in order, two per row.
fn render_card_rows(
&self,
cards: &[GroupCandidate],
@@ -235,8 +230,6 @@ impl BrowsePanel {
.p_2()
.gap_2()
.children(first.map(|card| self.render_card(card, cx)))
// Keep an odd last card in one column: an empty spacer
// takes the second slot so the card cannot stretch.
.child(match second {
Some(card) => self.render_card(card, cx),
None => div().flex_1().into_any_element(),
@@ -339,7 +332,7 @@ impl BrowsePanel {
.text_sm()
.text_color(cx.theme().text_muted)
.text_ellipsis()
.line_clamp(3)
.line_clamp(2)
.map(|this| {
if let Some(about) = about {
this.child(about)
@@ -458,28 +451,31 @@ impl Render for BrowsePanel {
v_flex()
.size_full()
.child(
h_flex()
.gap_2()
.px_2()
v_flex()
.h_32()
.flex_shrink_0()
.child(Input::new(&self.input).cleanable(true).flex_1())
.items_center()
.justify_center()
.bg(cx.theme().surface_background)
.child(
Button::new("browse-go")
.label("Go")
.primary()
.on_click(cx.listener(|this, _event, window, cx| {
this.browse(window, cx);
})),
)
.when(self.loading || (discover && discovering), |this| {
this.child(Indicator::new().small().color(cx.theme().icon_accent))
}),
h_flex()
.w_full()
.max_w_56()
.gap_1()
.child(Input::new(&self.input).cleanable(true).flex_1())
.child(Button::new("browse-go").label("Go").primary().on_click(
cx.listener(|this, _event, window, cx| {
this.browse(window, cx);
}),
)),
),
)
.child(
div()
.flex_1()
.min_h_0()
.relative()
.px_2()
.child(body)
.child(Scrollbar::vertical(&self.scroll_handle)),
)