damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 84174ef9adf01488f8863f13878dd25e31943afc
parent f78eeb1f22a14d818fe0d9291c4f55813c882d1c
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  7 May 2023 10:28:36 -0700

Ping relays on resume, if there's an error then try to reconnect

This is an attempt to fix the fail-to-reconnect issues. Let's see if it works.

Diffstat:
Mdamus/ContentView.swift | 18++++++++++++++++++
Mdamus/Nostr/RelayConnection.swift | 23++++++++++++++++++++---
Mdamus/Nostr/RelayPool.swift | 8+++++++-
Mdamus/Nostr/WebSocket.swift | 4++++
4 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -59,6 +59,8 @@ struct ContentView: View { return keypair.privkey } + @Environment(\.scenePhase) var scenePhase + @State var status: String = "Not connected" @State var active_sheet: Sheets? = nil @State var damus_state: DamusState? = nil @@ -403,6 +405,22 @@ struct ContentView: View { .onReceive(handle_notify(.unmute_thread)) { notif in home.filter_events() } + .onChange(of: scenePhase) { (phase: ScenePhase) in + switch phase { + case .background: + print("📙 DAMUS BACKGROUNDED") + break + case .inactive: + print("📙 DAMUS INACTIVE") + break + case .active: + print("📙 DAMUS ACTIVE") + guard let ds = damus_state else { return } + ds.pool.ping() + @unknown default: + break + } + } .onReceive(handle_notify(.local_notification)) { notif in guard let local = notif.object as? LossyLocalNotification, diff --git a/damus/Nostr/RelayConnection.swift b/damus/Nostr/RelayConnection.swift @@ -42,6 +42,7 @@ final class RelayConnection { private(set) var isConnecting = false private(set) var last_connection_attempt: TimeInterval = 0 + private(set) var last_pong: Date? = nil private(set) var backoff: TimeInterval = 1.0 private lazy var socket = WebSocket(url.url) private var subscriptionToken: AnyCancellable? @@ -54,6 +55,18 @@ final class RelayConnection { self.handleEvent = handleEvent } + func ping() { + socket.ping { err in + if let err { + self.isConnecting = false + self.isConnected = false + self.reconnect_with_backoff() + } else { + self.last_pong = .now + } + } + } + func connect(force: Bool = false) { if !force && (isConnected || isConnecting) { return @@ -111,15 +124,14 @@ final class RelayConnection { DispatchQueue.main.async { self.isConnected = false self.isConnecting = false - self.reconnect() + self.reconnect_with_backoff() } case .error(let error): print("⚠️ Warning: RelayConnection (\(self.url)) error: \(error)") DispatchQueue.main.async { self.isConnected = false self.isConnecting = false - self.backoff *= 1.5 - self.reconnect_in(after: self.backoff) + self.reconnect_with_backoff() } } DispatchQueue.main.async { @@ -127,6 +139,11 @@ final class RelayConnection { } } + func reconnect_with_backoff() { + self.backoff *= 1.5 + self.reconnect_in(after: self.backoff) + } + func reconnect() { guard !isConnecting else { return // we're already trying to connect diff --git a/damus/Nostr/RelayPool.swift b/damus/Nostr/RelayPool.swift @@ -79,7 +79,13 @@ class RelayPool { self.handlers = handlers.filter { $0.sub_id != sub_id } print("removing \(sub_id) handler, current: \(handlers.count)") } - + + func ping() { + for relay in relays { + relay.connection.ping() + } + } + func register_handler(sub_id: String, handler: @escaping (String, NostrConnectionEvent) -> ()) { for handler in handlers { // don't add duplicate handlers diff --git a/damus/Nostr/WebSocket.swift b/damus/Nostr/WebSocket.swift @@ -32,6 +32,10 @@ final class WebSocket: NSObject, URLSessionWebSocketDelegate { self.session = session } + func ping(receiveHandler: @escaping (Error?) -> Void) { + self.webSocketTask.sendPing(pongReceiveHandler: receiveHandler) + } + func connect() { resume() }