damus

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

commit d55d0d61ed1cbeb883772d5e49d6db051ecce5b5
parent cf904805017f7a32b2f508e9ca77a1e5a87befa4
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 15 Feb 2023 09:35:47 -0800

perf: debounce incoming dms

This fixes perf issues on startup if you have lots of dms

Changelog-Fixed: Fix lag on startup when you have lots of DMs
Changelog-Fixed: Fix an issues where dm notifications appear without any new events

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/Models/HomeModel.swift | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */; }; 4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8B28398BC6008A31F1 /* Keys.swift */; }; 4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */; }; + 4C2CDDF7299D4A5E00879FD5 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */; }; 4C363A8428233689006E126D /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8328233689006E126D /* Parser.swift */; }; 4C363A8828236948006E126D /* BlocksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8728236948006E126D /* BlocksView.swift */; }; 4C363A8A28236B57006E126D /* MentionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8928236B57006E126D /* MentionView.swift */; }; @@ -312,6 +313,7 @@ 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePictureSelector.swift; sourceTree = "<group>"; }; 4C285C8B28398BC6008A31F1 /* Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = "<group>"; }; 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveKeysView.swift; sourceTree = "<group>"; }; + 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; }; 4C363A8328233689006E126D /* Parser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; }; 4C363A8728236948006E126D /* BlocksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocksView.swift; sourceTree = "<group>"; }; 4C363A8928236B57006E126D /* MentionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionView.swift; sourceTree = "<group>"; }; @@ -780,6 +782,7 @@ 4CB883A72975FC1800DC99E7 /* Zaps.swift */, 4CB883B5297730E400DC99E7 /* LNUrls.swift */, 3AB72AB8298ECF30004BB58C /* Translator.swift */, + 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */, ); path = Util; sourceTree = "<group>"; @@ -1342,6 +1345,7 @@ 4CE879552996BAB900F758CC /* RelayPaidDetail.swift in Sources */, 4CF0ABD42980996B00D66079 /* Report.swift in Sources */, 4C06670B28FDE64700038D2A /* damus.c in Sources */, + 4C2CDDF7299D4A5E00879FD5 /* Debouncer.swift in Sources */, 3AAA95CC298E07E900F3D526 /* DeepLPlan.swift in Sources */, 4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */, 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */, diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift @@ -38,6 +38,9 @@ class HomeModel: ObservableObject { var channels: [String: NostrEvent] = [:] var last_event_of_kind: [String: [Int: NostrEvent]] = [:] var done_init: Bool = false + var incoming_dms: [NostrEvent] = [] + let dm_debouncer = Debouncer(interval: 0.5) + var should_debounce_dms = true let home_subid = UUID().description let contacts_subid = UUID().description @@ -56,16 +59,25 @@ class HomeModel: ObservableObject { init() { self.damus_state = DamusState.empty self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) + self.setup_debouncer() } init(damus_state: DamusState) { self.damus_state = damus_state self.dms = DirectMessagesModel(our_pubkey: damus_state.pubkey) + self.setup_debouncer() } var pool: RelayPool { return damus_state.pool } + + func setup_debouncer() { + // turn off debouncer after initial load + DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { + self.should_debounce_dms = false + } + } func has_sub_id_event(sub_id: String, ev_id: String) -> Bool { if !has_event.keys.contains(sub_id) { @@ -303,7 +315,8 @@ class HomeModel: ObservableObject { case .eose(let sub_id): if sub_id == dms_subid { - let dms = dms.dms.flatMap { $0.1.events } + var dms = dms.dms.flatMap { $0.1.events } + dms.append(contentsOf: incoming_dms) load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: dms, damus_state: damus_state) } else if sub_id == notifications_subid { load_profiles(profiles_subid: profiles_subid, relay_id: relay_id, events: notifications, damus_state: damus_state) @@ -477,10 +490,28 @@ class HomeModel: ObservableObject { handle_notification(ev: ev) } } - + func handle_dm(_ ev: NostrEvent) { - if let notifs = handle_incoming_dm(contacts: damus_state.contacts, prev_events: self.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, ev: ev) { - self.new_events = notifs + guard should_show_event(contacts: damus_state.contacts, ev: ev) else { + return + } + + if !should_debounce_dms { + self.incoming_dms.append(ev) + if let notifs = handle_incoming_dms(contacts: self.damus_state.contacts, prev_events: self.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, evs: self.incoming_dms) { + self.new_events = notifs + } + self.incoming_dms = [] + return + } + + incoming_dms.append(ev) + + dm_debouncer.debounce { + if let notifs = handle_incoming_dms(contacts: self.damus_state.contacts, prev_events: self.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, evs: self.incoming_dms) { + self.new_events = notifs + } + self.incoming_dms = [] } } } @@ -761,14 +792,10 @@ func fetch_relay_metadata(relay_id: String) async throws -> RelayMetadata? { func process_relay_metadata() { } -func handle_incoming_dm(contacts: Contacts, prev_events: NewEventsBits, dms: DirectMessagesModel, our_pubkey: String, ev: NostrEvent) -> NewEventsBits? { - // hide blocked users - guard should_show_event(contacts: contacts, ev: ev) else { - return prev_events - } - +func handle_incoming_dm(ev: NostrEvent, our_pubkey: String, dms: DirectMessagesModel, prev_events: NewEventsBits) -> (Bool, NewEventsBits?) { var inserted = false var found = false + let ours = ev.pubkey == our_pubkey var i = 0 @@ -795,15 +822,32 @@ func handle_incoming_dm(contacts: Contacts, prev_events: NewEventsBits, dms: Dir } if !found { - inserted = true let model = DirectMessageModel(events: [ev], our_pubkey: our_pubkey) dms.dms.append((the_pk, model)) } + + var new_bits: NewEventsBits? = nil + if inserted { + new_bits = handle_last_events(new_events: prev_events, ev: ev, timeline: .dms, shouldNotify: !ours) + } + + return (inserted, new_bits) +} + +func handle_incoming_dms(contacts: Contacts, prev_events: NewEventsBits, dms: DirectMessagesModel, our_pubkey: String, evs: [NostrEvent]) -> NewEventsBits? { + var inserted = false var new_events: NewEventsBits? = nil + + for ev in evs { + let res = handle_incoming_dm(ev: ev, our_pubkey: our_pubkey, dms: dms, prev_events: prev_events) + inserted = res.0 || inserted + if let new = res.1 { + new_events = new + } + } + if inserted { - new_events = handle_last_events(new_events: prev_events, ev: ev, timeline: .dms, shouldNotify: !ours) - dms.dms = dms.dms.filter({ $0.1.events.count > 0 }).sorted { a, b in return a.1.events.last!.created_at > b.1.events.last!.created_at }