commit 3824e95f296719fd8cf8a266f89e163cfce15cc4
parent 2867da61ca9c1414fd23345d8d6d4c572755a6ce
Author: William Casarin <jb55@jb55.com>
Date: Thu, 29 Dec 2022 15:23:34 -0800
relays: keep in sync with user relay list
Still need to figure out how to ensure new bootstrap relays are added...
Changelog-Changed: Ensure contact relay list is kept in sync with internal relay pool
Diffstat:
8 files changed, 87 insertions(+), 49 deletions(-)
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
@@ -15,6 +15,7 @@ var BOOTSTRAP_RELAYS = [
"wss://nostr.fmt.wiz.biz",
"wss://relay.nostr.bg",
"wss://nostr.oxtr.dev",
+ "wss://nostr.v0l.io",
]
struct TimestampedProfile {
diff --git a/damus/Models/Contacts.swift b/damus/Models/Contacts.swift
@@ -139,13 +139,8 @@ func decode_json_relays(_ content: String) -> [String: RelayInfo]? {
return decode_json(content)
}
-func remove_relay(ev: NostrEvent, privkey: String, relay: String) -> NostrEvent? {
- let damus_relay = RelayDescriptor(url: URL(string: "wss://relay.damus.io")!, info: .rw)
-
- var relays = ensure_relay_info(relays: [damus_relay], content: ev.content)
- guard relays.index(forKey: relay) != nil else {
- return nil
- }
+func remove_relay(ev: NostrEvent, current_relays: [RelayDescriptor], privkey: String, relay: String) -> NostrEvent? {
+ var relays = ensure_relay_info(relays: current_relays, content: ev.content)
relays.removeValue(forKey: relay)
diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift
@@ -446,21 +446,7 @@ func add_contact_if_friend(contacts: Contacts, ev: NostrEvent) {
contacts.add_friend_contact(ev)
}
-func load_our_contacts(contacts: Contacts, our_pubkey: String, ev: NostrEvent) {
- guard ev.pubkey == our_pubkey else {
- return
- }
-
- // only use new stuff
- if let current_ev = contacts.event {
- guard ev.created_at > current_ev.created_at else {
- return
- }
- }
-
- let m_old_ev = contacts.event
- contacts.event = ev
-
+func load_our_contacts(contacts: Contacts, our_pubkey: String, m_old_ev: NostrEvent?, ev: NostrEvent) {
var new_pks = Set<String>()
// our contacts
for tag in ev.tags {
@@ -572,35 +558,68 @@ func robohash(_ pk: String) -> String {
return "https://robohash.org/" + pk
}
-func process_contact_event(pool: RelayPool, contacts: Contacts, pubkey: String, ev: NostrEvent) {
- load_our_contacts(contacts: contacts, our_pubkey: pubkey, ev: ev)
- load_our_relays(contacts: contacts, our_pubkey: pubkey, pool: pool, ev: ev)
- add_contact_if_friend(contacts: contacts, ev: ev)
-}
-
-func load_our_relays(contacts: Contacts, our_pubkey: String, pool: RelayPool, ev: NostrEvent) {
- guard ev.pubkey == our_pubkey else {
+func load_our_stuff(pool: RelayPool, contacts: Contacts, pubkey: String, ev: NostrEvent) {
+ guard ev.pubkey == pubkey else {
return
}
- // only load new stuff
- if let old_contacts = contacts.event {
- guard ev.created_at > old_contacts.created_at else {
+ // only use new stuff
+ if let current_ev = contacts.event {
+ guard ev.created_at > current_ev.created_at else {
return
}
}
+
+ let m_old_ev = contacts.event
+ contacts.event = ev
+
+ load_our_contacts(contacts: contacts, our_pubkey: pubkey, m_old_ev: m_old_ev, ev: ev)
+ load_our_relays(contacts: contacts, our_pubkey: pubkey, pool: pool, m_old_ev: m_old_ev, ev: ev)
+}
+func process_contact_event(pool: RelayPool, contacts: Contacts, pubkey: String, ev: NostrEvent) {
+ load_our_stuff(pool: pool, contacts: contacts, pubkey: pubkey, ev: ev)
+ add_contact_if_friend(contacts: contacts, ev: ev)
+}
+
+func load_our_relays(contacts: Contacts, our_pubkey: String, pool: RelayPool, m_old_ev: NostrEvent?, ev: NostrEvent) {
+ let bootstrap_dict: [String: RelayInfo] = [:]
+ let old_decoded = m_old_ev.flatMap { decode_json_relays($0.content) } ?? BOOTSTRAP_RELAYS.reduce(into: bootstrap_dict) { (d, r) in
+ d[r] = .rw
+ }
+
guard let decoded = decode_json_relays(ev.content) else {
return
}
-
+
+ var changed = false
+
+ var new = Set<String>()
for key in decoded.keys {
- if let url = URL(string: key) {
- if let _ = try? pool.add_relay(url, info: decoded[key]!) {
- pool.connect(to: [key])
+ new.insert(key)
+ }
+
+ var old = Set<String>()
+ for key in old_decoded.keys {
+ old.insert(key)
+ }
+
+ let diff = old.symmetricDifference(new)
+
+ for d in diff {
+ changed = true
+ if new.contains(d) {
+ if let url = URL(string: d) {
+ try? pool.add_relay(url, info: decoded[d] ?? .rw)
}
+ } else {
+ pool.remove_relay(d)
}
}
+
+ if changed {
+ notify(.relays_changed, ())
+ }
}
diff --git a/damus/Nostr/Relay.swift b/damus/Nostr/Relay.swift
@@ -28,12 +28,14 @@ class Relay: Identifiable {
let descriptor: RelayDescriptor
let connection: RelayConnection
+ var last_pong: UInt32
var flags: Int
init(descriptor: RelayDescriptor, connection: RelayConnection) {
self.flags = 0
self.descriptor = descriptor
self.connection = connection
+ self.last_pong = 0
}
func mark_broken() {
diff --git a/damus/Nostr/RelayPool.swift b/damus/Nostr/RelayPool.swift
@@ -179,8 +179,23 @@ class RelayPool {
return nil
}
-
+
+ func record_last_pong(relay_id: String, event: NostrConnectionEvent) {
+ if case .ws_event(let ws_event) = event {
+ if case .pong = ws_event {
+ for relay in relays {
+ if relay.id == relay_id {
+ relay.last_pong = UInt32(Date.now.timeIntervalSince1970)
+ return
+ }
+ }
+ }
+ }
+ }
+
func handle_event(relay_id: String, event: NostrConnectionEvent) {
+ record_last_pong(relay_id: relay_id, event: event)
+
// handle reconnect logic, etc?
for handler in handlers {
handler.callback(relay_id, event)
@@ -193,3 +208,4 @@ func add_rw_relay(_ pool: RelayPool, _ url: String) {
try? pool.add_relay(url_, info: RelayInfo.rw)
}
+
diff --git a/damus/Util/Notifications.swift b/damus/Util/Notifications.swift
@@ -14,6 +14,12 @@ extension Notification.Name {
}
extension Notification.Name {
+ static var relays_changed: Notification.Name {
+ return Notification.Name("relays_changed")
+ }
+}
+
+extension Notification.Name {
static var select_event: Notification.Name {
return Notification.Name("select_event")
}
diff --git a/damus/Views/ConfigView.swift b/damus/Views/ConfigView.swift
@@ -41,13 +41,9 @@ struct ConfigView: View {
var body: some View {
ZStack(alignment: .leading) {
Form {
- if let ev = state.contacts.event {
- Section("Relays") {
- if let relays = decode_json_relays(ev.content) {
- List(Array(relays.keys.sorted()), id: \.self) { relay in
- RelayView(state: state, ev: ev, relay: relay)
- }
- }
+ Section("Relays") {
+ List(Array(state.pool.relays), id: \.descriptor.url) { relay in
+ RelayView(state: state, relay: relay.descriptor.url.absoluteString)
}
}
@@ -113,7 +109,6 @@ struct ConfigView: View {
}
.sheet(isPresented: $show_add_relay) {
AddRelayView(show_add_relay: $show_add_relay, relay: $new_relay) { m_relay in
-
guard let relay = m_relay else {
return
}
diff --git a/damus/Views/RelayView.swift b/damus/Views/RelayView.swift
@@ -9,7 +9,6 @@ import SwiftUI
struct RelayView: View {
let state: DamusState
- let ev: NostrEvent
let relay: String
let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()
@@ -46,7 +45,12 @@ struct RelayView: View {
.swipeActions {
if let privkey = state.keypair.privkey {
Button {
- guard let new_ev = remove_relay( ev: ev, privkey: privkey, relay: relay) else {
+ guard let ev = state.contacts.event else {
+ return
+ }
+
+ let descriptors = state.pool.descriptors
+ guard let new_ev = remove_relay( ev: ev, current_relays: descriptors, privkey: privkey, relay: relay) else {
return
}
@@ -64,6 +68,6 @@ struct RelayView: View {
struct RelayView_Previews: PreviewProvider {
static var previews: some View {
- RelayView(state: test_damus_state(), ev: NostrEvent(content: "content", pubkey: "pk"), relay: "wss://relay.damus.io", conn_color: .red)
+ RelayView(state: test_damus_state(), relay: "wss://relay.damus.io", conn_color: .red)
}
}