damus

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

commit 19ba020bd04f82f191c57015a11753fd6d9b6c68
parent 43a5bbd53a91d727db76c0f31e84433bb0d91f8b
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Mon, 22 Apr 2024 23:09:30 +0000

contacts: save first list to storage during onboarding

This commit adds a mechanism to add the contact list to storage as soon
as it is generated, and thus it reduces the risk of poor network
conditions causing issues.

Changelog-Fixed: Improve reliability of contact list creation during onboarding
Closes: https://github.com/damus-io/damus/issues/2057
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Link: 20240422230912.65056-3-daniel@daquino.me
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus/ContentView.swift | 5+----
Mdamus/Models/UserSettingsStore.swift | 8++++++++
Mdamus/Nostr/RelayPool.swift | 22+++++++++++++---------
Mdamus/Views/SaveKeysView.swift | 28+++++++++++++++++++++++++---
4 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -680,10 +680,7 @@ struct ContentView: View { let relay_filters = RelayFilters(our_pubkey: pubkey) let bootstrap_relays = load_bootstrap_relays(pubkey: pubkey) - // dumb stuff needed for property wrappers - UserSettingsStore.pubkey = pubkey - let settings = UserSettingsStore() - UserSettingsStore.shared = settings + let settings = UserSettingsStore.globally_load_for(pubkey: pubkey) let new_relay_filters = load_relay_filters(pubkey) == nil for relay in bootstrap_relays { diff --git a/damus/Models/UserSettingsStore.swift b/damus/Models/UserSettingsStore.swift @@ -96,6 +96,14 @@ class UserSettingsStore: ObservableObject { static var shared: UserSettingsStore? = nil static var bool_options = Set<String>() + static func globally_load_for(pubkey: Pubkey) -> UserSettingsStore { + // dumb stuff needed for property wrappers + UserSettingsStore.pubkey = pubkey + let settings = UserSettingsStore() + UserSettingsStore.shared = settings + return settings + } + @StringSetting(key: "default_wallet", default_value: .system_default_wallet) var default_wallet: Wallet diff --git a/damus/Nostr/RelayPool.swift b/damus/Nostr/RelayPool.swift @@ -226,19 +226,23 @@ class RelayPool { print("queueing request for \(relay)") request_queue.append(QueuedRequest(req: r, relay: relay, skip_ephemeral: skip_ephemeral)) } + + func send_raw_to_local_ndb(_ req: NostrRequestType) { + // send to local relay (nostrdb) + switch req { + case .typical(let r): + if case .event = r, let rstr = make_nostr_req(r) { + let _ = ndb.process_client_event(rstr) + } + case .custom(let string): + let _ = ndb.process_client_event(string) + } + } func send_raw(_ req: NostrRequestType, to: [RelayURL]? = nil, skip_ephemeral: Bool = true) { let relays = to.map{ get_relays($0) } ?? self.relays - // send to local relay (nostrdb) - switch req { - case .typical(let r): - if case .event = r, let rstr = make_nostr_req(r) { - let _ = ndb.process_client_event(rstr) - } - case .custom(let string): - let _ = ndb.process_client_event(string) - } + self.send_raw_to_local_ndb(req) for relay in relays { if req.is_read && !(relay.descriptor.info.read ?? true) { diff --git a/damus/Views/SaveKeysView.swift b/damus/Views/SaveKeysView.swift @@ -21,6 +21,13 @@ struct SaveKeysView: View { @FocusState var pubkey_focused: Bool @FocusState var privkey_focused: Bool + let first_contact_event: NdbNote? + + init(account: CreateAccountModel) { + self.account = account + self.first_contact_event = make_first_contact_event(keypair: account.keypair) + } + var body: some View { ZStack(alignment: .top) { VStack(alignment: .center) { @@ -102,6 +109,13 @@ struct SaveKeysView: View { } func complete_account_creation(_ account: CreateAccountModel) { + guard let first_contact_event else { + error = NSLocalizedString("Could not create your initial contact list event. This is a software bug, please contact Damus support via support@damus.io or through our Nostr account for help.", comment: "Error message to the user indicating that the initial contact list failed to be created.") + return + } + // Save contact list to storage right away so that we don't need to depend on the network to complete this important step + self.save_to_storage(first_contact_event: first_contact_event, for: account) + let bootstrap_relays = load_bootstrap_relays(pubkey: account.pubkey) for relay in bootstrap_relays { add_rw_relay(self.pool, relay) @@ -115,6 +129,15 @@ struct SaveKeysView: View { self.pool.connect() } + + func save_to_storage(first_contact_event: NdbNote, for account: CreateAccountModel) { + // Send to NostrDB so that we have a local copy in storage + self.pool.send_raw_to_local_ndb(.typical(.event(first_contact_event))) + + // Save the ID to user settings so that we can easily find it later. + let settings = UserSettingsStore.globally_load_for(pubkey: account.pubkey) + settings.latest_contact_event_id_hex = first_contact_event.id.hex() + } func handle_event(relay: RelayURL, ev: NostrConnectionEvent) { switch ev { @@ -122,15 +145,14 @@ struct SaveKeysView: View { switch wsev { case .connected: let metadata = create_account_to_metadata(account) - let contacts_ev = make_first_contact_event(keypair: account.keypair) if let keypair = account.keypair.to_full(), let metadata_ev = make_metadata_event(keypair: keypair, metadata: metadata) { self.pool.send(.event(metadata_ev)) } - if let contacts_ev { - self.pool.send(.event(contacts_ev)) + if let first_contact_event { + self.pool.send(.event(first_contact_event)) } do {