commit d1cced8d5424ae893c6a75a324ce6a0720a01c6c
parent 8849b6105c21089b6d42d3ac0dc8fad75bf59b96
Author: Daniel D’Aquino <daniel@daquino.me>
Date: Fri, 28 Mar 2025 11:25:11 -0300
Fetch NIP-65 relay lists from profile view
Changelog-Fixed: Fixed issue where profiles with a NIP-65 relay list would not display on Damus
Closes: https://github.com/damus-io/damus/issues/2120
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Diffstat:
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/damus/Models/ProfileModel.swift b/damus/Models/ProfileModel.swift
@@ -10,8 +10,18 @@ import Foundation
class ProfileModel: ObservableObject, Equatable {
@Published var contacts: NostrEvent? = nil
@Published var following: Int = 0
- @Published var relays: [RelayURL: LegacyKind3RelayRWConfiguration]? = nil
+ @Published var relay_list: NIP65.RelayList? = nil
+ @Published var legacy_relay_list: [RelayURL: LegacyKind3RelayRWConfiguration]? = nil
@Published var progress: Int = 0
+ var relay_urls: [RelayURL]? {
+ if let relay_list {
+ return relay_list.relays.values.map({ $0.url })
+ }
+ if let legacy_relay_list {
+ return Array(legacy_relay_list.keys)
+ }
+ return nil
+ }
private let MAX_SHARE_RELAYS = 4
@@ -69,6 +79,7 @@ class ProfileModel: ObservableObject, Equatable {
func subscribe() {
var text_filter = NostrFilter(kinds: [.text, .longform, .highlight])
var profile_filter = NostrFilter(kinds: [.contacts, .metadata, .boost])
+ var relay_list_filter = NostrFilter(kinds: [.relay_list], authors: [pubkey])
profile_filter.authors = [pubkey]
@@ -78,7 +89,7 @@ class ProfileModel: ObservableObject, Equatable {
print("subscribing to textlike events from profile \(pubkey) with sub_id \(sub_id)")
//print_filters(relay_id: "profile", filters: [[text_filter], [profile_filter]])
damus.nostrNetwork.pool.subscribe(sub_id: sub_id, filters: [text_filter], handler: handle_event)
- damus.nostrNetwork.pool.subscribe(sub_id: prof_subid, filters: [profile_filter], handler: handle_event)
+ damus.nostrNetwork.pool.subscribe(sub_id: prof_subid, filters: [profile_filter, relay_list_filter], handler: handle_event)
subscribe_to_conversations()
}
@@ -109,7 +120,7 @@ class ProfileModel: ObservableObject, Equatable {
self.contacts = ev
self.following = count_pubkeys(ev.tags)
- self.relays = decode_json_relays(ev.content)
+ self.legacy_relay_list = decode_json_relays(ev.content)
}
private func add_event(_ ev: NostrEvent) {
@@ -120,6 +131,9 @@ class ProfileModel: ObservableObject, Equatable {
} else if ev.known_kind == .contacts {
handle_profile_contact_event(ev)
}
+ else if ev.known_kind == .relay_list {
+ self.relay_list = try? NIP65.RelayList(event: ev) // Whether another user's list is malformatted is something beyond our control. Probably best to suppress errors
+ }
seen_event.insert(ev.id)
}
@@ -192,7 +206,7 @@ class ProfileModel: ObservableObject, Equatable {
private func findRelaysHandler(relay_id: RelayURL, ev: NostrConnectionEvent) {
if case .nostr_event(let resp) = ev, case .event(_, let event) = resp, case .contacts = event.known_kind {
- self.relays = decode_json_relays(event.content)
+ self.legacy_relay_list = decode_json_relays(event.content)
}
}
@@ -208,7 +222,7 @@ class ProfileModel: ObservableObject, Equatable {
}
func getCappedRelayStrings() -> [String] {
- return relays?.keys.prefix(MAX_SHARE_RELAYS).map { $0.absoluteString } ?? []
+ return self.relay_urls?.prefix(MAX_SHARE_RELAYS).map { $0.absoluteString } ?? []
}
}
diff --git a/damus/Views/Profile/ProfileView.swift b/damus/Views/Profile/ProfileView.swift
@@ -396,18 +396,18 @@ struct ProfileView: View {
}
}
- if let relays = profile.relays {
+ if let relays = profile.relay_urls {
// Only open relay config view if the user is logged in with private key and they are looking at their own profile.
- let noun_string = pluralizedString(key: "relays_count", count: relays.keys.count)
+ let noun_string = pluralizedString(key: "relays_count", count: relays.count)
let noun_text = Text(noun_string).font(.subheadline).foregroundColor(.gray)
- let relay_text = Text("\(Text(verbatim: relays.keys.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
+ let relay_text = Text("\(Text(verbatim: relays.count.formatted()).font(.subheadline.weight(.medium))) \(noun_text)", comment: "Sentence composed of 2 variables to describe how many relay servers a user is connected. In source English, the first variable is the number of relay servers, and the second variable is 'Relay' or 'Relays'.")
if profile.pubkey == damus_state.pubkey && damus_state.is_privkey_user {
NavigationLink(value: Route.RelayConfig) {
relay_text
}
.buttonStyle(PlainButtonStyle())
} else {
- NavigationLink(value: Route.UserRelays(relays: Array(relays.keys).sorted())) {
+ NavigationLink(value: Route.UserRelays(relays: relays.sorted())) {
relay_text
}
.buttonStyle(PlainButtonStyle())