1
0
mirror of git://jb55.com/damus synced 2024-09-29 16:30:44 +00:00

contacts: save the users' latest contact event ID

... to a persistent setting, and try to load it from NostrDB on app start.

This commit causes the user's contact list event ID to be saved
persistently as a user-specific setting, and to be loaded immediately
after startup from the local NostrDB instance.

This helps improve reliability around contact lists, since we previously
relied on fetching that contact list from other relays.

Eventually we will not need the event ID to be stored at all, as we will
be able to query NostrDB, but for now having the latest event ID
persistently stored will allow us to get around this limitation in the
cleanest possible way (i.e. without having to store the event itself
into another mechanism, and migrating it later to NostrDB)

Other notes:

- It uses a mechanism similar to other user settings, so it is
  pubkey-specific and should handle login/logout cases

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240422230912.65056-2-daniel@daquino.me
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
Daniel D’Aquino 2024-04-22 23:09:27 +00:00
parent ada99418f6
commit bb321b6e8a
3 changed files with 50 additions and 4 deletions

View File

@ -7,7 +7,6 @@
import Foundation
class Contacts {
private var friends: Set<Pubkey> = Set()
private var friend_of_friends: Set<Pubkey> = Set()
@ -15,7 +14,13 @@ class Contacts {
private var pubkey_to_our_friends = [Pubkey : Set<Pubkey>]()
let our_pubkey: Pubkey
var event: NostrEvent?
var delegate: ContactsDelegate? = nil
var event: NostrEvent? {
didSet {
guard let event else { return }
self.delegate?.latest_contact_event_changed(new_event: event)
}
}
init(our_pubkey: Pubkey) {
self.our_pubkey = our_pubkey
@ -88,3 +93,8 @@ class Contacts {
return Array((pubkey_to_our_friends[pubkey] ?? Set()))
}
}
/// Delegate protocol for `Contacts`. Use this to listen to significant updates from a `Contacts` instance
protocol ContactsDelegate {
func latest_contact_event_changed(new_event: NostrEvent)
}

View File

@ -41,11 +41,15 @@ enum HomeResubFilter {
}
}
class HomeModel {
class HomeModel: ContactsDelegate {
// Don't trigger a user notification for events older than a certain age
static let event_max_age_for_notification: TimeInterval = EVENT_MAX_AGE_FOR_NOTIFICATION
var damus_state: DamusState
var damus_state: DamusState {
didSet {
self.load_our_stuff_from_damus_state()
}
}
// NDBTODO: let's get rid of this entirely, let nostrdb handle it
var has_event: [String: Set<NoteId>] = [:]
@ -108,6 +112,32 @@ class HomeModel {
self.should_debounce_dms = false
}
}
// MARK: - Loading items from DamusState
/// This is called whenever DamusState gets set. This function is used to load or setup anything we need from the new DamusState
func load_our_stuff_from_damus_state() {
self.load_latest_contact_event_from_damus_state()
}
/// This loads the latest contact event we have on file from NostrDB. This should be called as soon as we get the new DamusState
/// Loading the latest contact list event into our `Contacts` instance from storage is important to avoid getting into weird states when the network is unreliable or when relays delete such information
func load_latest_contact_event_from_damus_state() {
guard let latest_contact_event_id_hex = damus_state.settings.latest_contact_event_id_hex else { return }
guard let latest_contact_event_id = NoteId(hex: latest_contact_event_id_hex) else { return }
guard let latest_contact_event: NdbNote = damus_state.ndb.lookup_note( latest_contact_event_id)?.unsafeUnownedValue?.to_owned() else { return }
process_contact_event(state: damus_state, ev: latest_contact_event)
damus_state.contacts.delegate = self
}
// MARK: - ContactsDelegate functions
func latest_contact_event_changed(new_event: NostrEvent) {
// When the latest user contact event has changed, save its ID so we know exactly where to find it next time
damus_state.settings.latest_contact_event_id_hex = new_event.id.hex()
}
// MARK: - Nostr event and subscription handling
func resubscribe(_ resubbing: Resubscribe) {
if self.should_debounce_dms {

View File

@ -312,6 +312,12 @@ class UserSettingsStore: ObservableObject {
return internal_winetranslate_api_key != nil
}
}
// MARK: Internal, hidden settings
@Setting(key: "latest_contact_event_id", default_value: nil)
var latest_contact_event_id_hex: String?
}
func pk_setting_key(_ pubkey: Pubkey, key: String) -> String {