Fix infinite loading spinner regression
Root cause: 1. `lookup` looks up a note by its note id, and saving its note key 2. `lookup` then returns early (i.e. does not loading anything from the network) since it found the note 3. On the view, once it borrows the note from NostrDB (a query using its NoteKey), the query fails (Most likely due to transaction inheritance and the fact that the inherited transaction may be an older snapshot of the database without the note), causing the view loading logic to fail silently, leading to the infinite loading spinner The issue was addressed by performing a single query during lookup and copying the note contents directly at that point to avoid this transaction inheritance issue. In the future we should consider a more comprehensive fix to address other instances where this may happen. I opened https://github.com/damus-io/damus/issues/3607 for this future work. Changelog-Fixed: Fixed an issue where notes would keep loading indefinitely in some cases Closes: https://github.com/damus-io/damus/issues/3498 Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -416,8 +416,8 @@ extension NostrNetworkManager {
|
|||||||
/// to all connected relays. The `timeout` parameter is a total deadline for both phases.
|
/// to all connected relays. The `timeout` parameter is a total deadline for both phases.
|
||||||
func lookup(noteId: NoteId, to targetRelays: [RelayURL]? = nil, timeout: Duration? = nil) async throws -> NdbNoteLender? {
|
func lookup(noteId: NoteId, to targetRelays: [RelayURL]? = nil, timeout: Duration? = nil) async throws -> NdbNoteLender? {
|
||||||
// Since note ids point to immutable objects, we can do a simple ndb lookup first
|
// Since note ids point to immutable objects, we can do a simple ndb lookup first
|
||||||
if let noteKey = try? self.ndb.lookup_note_key(noteId) {
|
if let note = try? self.ndb.lookup_note_and_copy(noteId) {
|
||||||
return NdbNoteLender(ndb: self.ndb, noteKey: noteKey)
|
return NdbNoteLender(ownedNdbNote: note)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not available in local ndb, stream from network
|
// Not available in local ndb, stream from network
|
||||||
@@ -760,4 +760,4 @@ extension NostrNetworkManager {
|
|||||||
/// Preload metadata for authors and referenced profiles
|
/// Preload metadata for authors and referenced profiles
|
||||||
case preload
|
case preload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ struct EventLoaderView<Content: View>: View {
|
|||||||
let relayHints: [RelayURL]
|
let relayHints: [RelayURL]
|
||||||
@State var event: NostrEvent?
|
@State var event: NostrEvent?
|
||||||
@State var subscription_uuid: String = UUID().description
|
@State var subscription_uuid: String = UUID().description
|
||||||
@State var loadingTask: Task<Void, Never>? = nil
|
|
||||||
let content: (NostrEvent) -> Content
|
let content: (NostrEvent) -> Content
|
||||||
|
|
||||||
/// Creates an event loader view.
|
/// Creates an event loader view.
|
||||||
@@ -34,32 +33,21 @@ struct EventLoaderView<Content: View>: View {
|
|||||||
let event = damus_state.events.lookup(event_id)
|
let event = damus_state.events.lookup(event_id)
|
||||||
_event = State(initialValue: event)
|
_event = State(initialValue: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unsubscribe() {
|
func load() async {
|
||||||
self.loadingTask?.cancel()
|
let targetRelays = relayHints.isEmpty ? nil : relayHints
|
||||||
}
|
#if DEBUG
|
||||||
|
if let targetRelays, !targetRelays.isEmpty {
|
||||||
func subscribe() {
|
print("[relay-hints] EventLoaderView: Loading event \(event_id.hex().prefix(8))... with \(targetRelays.count) relay hint(s): \(targetRelays.map { $0.absoluteString })")
|
||||||
self.loadingTask?.cancel()
|
|
||||||
self.loadingTask = Task {
|
|
||||||
let targetRelays = relayHints.isEmpty ? nil : relayHints
|
|
||||||
#if DEBUG
|
|
||||||
if let targetRelays, !targetRelays.isEmpty {
|
|
||||||
print("[relay-hints] EventLoaderView: Loading event \(event_id.hex().prefix(8))... with \(targetRelays.count) relay hint(s): \(targetRelays.map { $0.absoluteString })")
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
let lender = try? await damus_state.nostrNetwork.reader.lookup(noteId: self.event_id, to: targetRelays)
|
|
||||||
lender?.justUseACopy({ event = $0 })
|
|
||||||
#if DEBUG
|
|
||||||
if let targetRelays, !targetRelays.isEmpty {
|
|
||||||
print("[relay-hints] EventLoaderView: Event \(event_id.hex().prefix(8))... loaded: \(event != nil)")
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
|
let lender = try? await damus_state.nostrNetwork.reader.lookup(noteId: self.event_id, to: targetRelays)
|
||||||
func load() {
|
lender?.justUseACopy({ event = $0 })
|
||||||
subscribe()
|
#if DEBUG
|
||||||
|
if let targetRelays, !targetRelays.isEmpty {
|
||||||
|
print("[relay-hints] EventLoaderView: Event \(event_id.hex().prefix(8))... loaded: \(event != nil)")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -70,11 +58,11 @@ struct EventLoaderView<Content: View>: View {
|
|||||||
ProgressView().padding()
|
ProgressView().padding()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.task {
|
||||||
guard event == nil else {
|
guard event == nil else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.load()
|
await self.load()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user