damus

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

commit b8fe826b5877e907944a86cdd74d6709aaa23d58
parent 841c49238fce2aa870a7bdf1f51d2de76b57ddce
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Fri, 21 Mar 2025 20:43:10 -0300

Improve syncing and performance of ThreadModel

This commit introduces two minor improvements:
1. It ensures better consistency between ThreadModel and EventCache
2. It avoids unnecessary recursion calls on `add_event`

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>

Diffstat:
Mdamus/Models/ThreadModel.swift | 47++++++++++++++++++++++++++++++++++-------------
1 file changed, 34 insertions(+), 13 deletions(-)

diff --git a/damus/Models/ThreadModel.swift b/damus/Models/ThreadModel.swift @@ -29,7 +29,18 @@ class ThreadModel: ObservableObject { /// /// This is a computed property because we then don't need to worry about keeping things in sync var parent_events: [NostrEvent] { - return event_map.parent_events(of: selected_event) + // This block of code helps ensure `ThreadEventMap` stays in sync with `EventCache` + let parent_events_from_cache = damus_state.events.parent_events(event: selected_event, keypair: damus_state.keypair) + for parent_event in parent_events_from_cache { + add_event( + parent_event, + keypair: damus_state.keypair, + look_for_parent_events: false, // We have all parents we need for now + publish_changes: false // Publishing changes during a view render is problematic + ) + } + + return parent_events_from_cache } /// All of the direct and indirect replies of `selected_event` in the thread. sorted chronologically /// @@ -125,7 +136,13 @@ class ThreadModel: ObservableObject { /// Adds an event to this thread. /// Normally this does not need to be called externally because it is the responsibility of this class to load the events, not the view's. /// However, this can be called externally for testing purposes (e.g. injecting events for testing) - func add_event(_ ev: NostrEvent, keypair: Keypair) { + /// + /// - Parameters: + /// - ev: The event to add into the thread event map + /// - keypair: The user's keypair + /// - look_for_parent_events: Whether to search for parent events of the input event in NostrDB + /// - publish_changes: Whether to publish changes at the end + func add_event(_ ev: NostrEvent, keypair: Keypair, look_for_parent_events: Bool = true, publish_changes: Bool = true) { if event_map.contains(id: ev.id) { return } @@ -136,18 +153,22 @@ class ThreadModel: ObservableObject { event_map.add(event: ev) - // Add all parent events that we have on EventCache (and subsequently on NostrDB) - // This helps ensure we include as many locally-stored notes as possible — even on poor networking conditions - damus_state.events.parent_events(event: ev, keypair: damus_state.keypair).forEach { - // Note: Nostr threads are cryptographically guaranteeed to be acyclic graphs, which means there is no risk of infinite recursion in this call - add_event( - $0, // The `lookup` function in `parent_events` turns the event into an "owned" object, so we do not need to clone here - keypair: damus_state.keypair - ) + if look_for_parent_events { + // Add all parent events that we have on EventCache (and subsequently on NostrDB) + // This helps ensure we include as many locally-stored notes as possible — even on poor networking conditions + damus_state.events.parent_events(event: ev, keypair: damus_state.keypair).forEach { + add_event( + $0, // The `lookup` function in `parent_events` turns the event into an "owned" object, so we do not need to clone here + keypair: damus_state.keypair, + look_for_parent_events: false, // We do not need deep recursion + publish_changes: false // Do not publish changes multiple times + ) + } + } + + if publish_changes { + objectWillChange.send() } - - // Publish changes - objectWillChange.send() } /// Handles an incoming event from a relay pool