mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-27 12:45:20 +00:00
Courier: deposit in parallel when the only route is a send queue (#1368)
* Deposit with couriers in parallel when the only route is a send queue The courier path was nearly unreachable: NostrTransport claims any favorite with a known npub as "reachable" regardless of connectivity, and the mesh favorite exchange shares npubs, so for essentially every courier-eligible recipient the router picked Nostr's reachable branch. With no internet the message just sat in the relay send queue — in the flagship scenario (internet shutdown, mutual friend standing right there) the courier walked away carrying nothing. Add Transport.canDeliverPromptly(to:), defaulting to reachability for radio-backed transports; NostrTransport answers honestly by mirroring the relay manager's connection state (fail-closed behind Tor). When the chosen transport can't hand the message off promptly, the router now also deposits a sealed copy with connected couriers. Double delivery is harmless: receivers dedup by message ID, and delivered/read acks never downgrade the carried status. When relays are up, sends are trusted and no courier quota is spent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Track DM-relay connectivity, not any-relay, for prompt delivery Codex review: NostrRelayManager.isConnected is true when any relay is up, including geohash/custom relays — but private messages target the default (gift-wrap-capable) relay set and queue when none of those are connected. A lone geohash relay would have suppressed the parallel courier deposit while the DM sat in the queue. Publish a DM-scoped connectivity flag and drive canDeliverPromptly from it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
jack
Claude Fable 5
parent
75da63c9d7
commit
a66c591f8e
@@ -14,7 +14,13 @@ final class NostrTransport: Transport, @unchecked Sendable {
|
||||
let registerPendingGiftWrap: @MainActor (String) -> Void
|
||||
let sendEvent: @MainActor (NostrEvent) -> Void
|
||||
let scheduleAfter: @Sendable (TimeInterval, @escaping @Sendable () -> Void) -> Void
|
||||
/// Emits whether a relay that carries private messages is up
|
||||
/// (fail-closed behind Tor). A connected geohash/custom relay alone
|
||||
/// doesn't count: DM sends target the default relay set and would
|
||||
/// still queue.
|
||||
let relayConnectivity: @MainActor () -> AnyPublisher<Bool, Never>
|
||||
|
||||
@MainActor
|
||||
static func live(idBridge: NostrIdentityBridge) -> Dependencies {
|
||||
Dependencies(
|
||||
notificationCenter: .default,
|
||||
@@ -26,7 +32,8 @@ final class NostrTransport: Transport, @unchecked Sendable {
|
||||
sendEvent: { NostrRelayManager.shared.sendEvent($0) },
|
||||
scheduleAfter: { delay, action in
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: action)
|
||||
}
|
||||
},
|
||||
relayConnectivity: { NostrRelayManager.shared.$isDMRelayConnected.eraseToAnyPublisher() }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -49,6 +56,10 @@ final class NostrTransport: Transport, @unchecked Sendable {
|
||||
|
||||
// Reachability Cache (thread-safe)
|
||||
private var reachablePeers: Set<PeerID> = []
|
||||
// Mirror of the relay manager's connection state, cached here because
|
||||
// canDeliverPromptly is called synchronously off the main actor.
|
||||
private var relaysConnected = false
|
||||
private var relayConnectivityCancellable: AnyCancellable?
|
||||
private let queue = DispatchQueue(label: "nostr.transport.state", attributes: .concurrent)
|
||||
|
||||
@MainActor
|
||||
@@ -72,6 +83,12 @@ final class NostrTransport: Transport, @unchecked Sendable {
|
||||
queue.sync(flags: .barrier) {
|
||||
self.reachablePeers = Set(reachable)
|
||||
}
|
||||
|
||||
relayConnectivityCancellable = self.dependencies.relayConnectivity()
|
||||
.sink { [weak self] connected in
|
||||
guard let self else { return }
|
||||
self.queue.async(flags: .barrier) { self.relaysConnected = connected }
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -133,6 +150,14 @@ final class NostrTransport: Transport, @unchecked Sendable {
|
||||
return reachablePeers.contains(where: { $0.toShort() == short })
|
||||
}
|
||||
}
|
||||
|
||||
func canDeliverPromptly(to peerID: PeerID) -> Bool {
|
||||
// A known npub makes a peer "reachable", but with no relay
|
||||
// connection a send only joins the local queue. Answering honestly
|
||||
// here lets the router hand a sealed copy to a courier in parallel
|
||||
// instead of waiting for internet that may never come.
|
||||
isPeerReachable(peerID) && queue.sync { relaysConnected }
|
||||
}
|
||||
|
||||
func peerNickname(peerID: PeerID) -> String? { nil }
|
||||
func getPeerNicknames() -> [PeerID: String] { [:] }
|
||||
|
||||
Reference in New Issue
Block a user