mirror of
git://jb55.com/damus
synced 2024-09-18 19:23:49 +00:00
Fix UI bug with user search and fix race conditions on profiles NIP-05 cache
Signed-off-by: Terry Yiu <git@tyiu.xyz> Reviewed-by: William Casarin <jb55@jb55.com> Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
3d0448a929
commit
640fbf23ea
@ -726,7 +726,7 @@ func process_metadata_profile(our_pubkey: String, profiles: Profiles, profile: P
|
|||||||
}
|
}
|
||||||
|
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
profiles.validated[ev.pubkey] = validated
|
profiles.set_validated(ev.pubkey, nip05: validated)
|
||||||
profiles.nip05_pubkey[nip05] = ev.pubkey
|
profiles.nip05_pubkey[nip05] = ev.pubkey
|
||||||
notify(.profile_updated, ProfileUpdate(pubkey: ev.pubkey, profile: profile))
|
notify(.profile_updated, ProfileUpdate(pubkey: ev.pubkey, profile: profile))
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ extension Trie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform breadth-first search from matching branch and collect values from all descendants.
|
// Perform breadth-first search from matching branch and collect values from all descendants.
|
||||||
let exactMatches = Array(currentNode.exactMatchValues)
|
|
||||||
var substringMatches = Set<V>(currentNode.substringMatchValues)
|
var substringMatches = Set<V>(currentNode.substringMatchValues)
|
||||||
var queue = Array(currentNode.children.values)
|
var queue = Array(currentNode.children.values)
|
||||||
|
|
||||||
@ -61,7 +60,8 @@ extension Trie {
|
|||||||
queue.append(contentsOf: node.children.values)
|
queue.append(contentsOf: node.children.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
return exactMatches + substringMatches
|
// Prioritize exact matches to be returned first, and then remove exact matches from the set of partial substring matches that are appended afterward.
|
||||||
|
return Array(currentNode.exactMatchValues) + (substringMatches.subtracting(currentNode.exactMatchValues))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts value of type V into this trie for the specified key. This function stores all substring endings of the key, not only the key itself.
|
/// Inserts value of type V into this trie for the specified key. This function stores all substring endings of the key, not only the key itself.
|
||||||
|
@ -13,12 +13,16 @@ class Profiles {
|
|||||||
|
|
||||||
/// This queue is used to synchronize access to the profiles dictionary, which
|
/// This queue is used to synchronize access to the profiles dictionary, which
|
||||||
/// prevents data races from crashing the app.
|
/// prevents data races from crashing the app.
|
||||||
private var queue = DispatchQueue(label: "io.damus.profiles",
|
private var profiles_queue = DispatchQueue(label: "io.damus.profiles",
|
||||||
qos: .userInteractive,
|
qos: .userInteractive,
|
||||||
attributes: .concurrent)
|
attributes: .concurrent)
|
||||||
|
|
||||||
|
private var validated_queue = DispatchQueue(label: "io.damus.profiles.validated",
|
||||||
|
qos: .userInteractive,
|
||||||
|
attributes: .concurrent)
|
||||||
|
|
||||||
private var profiles: [String: TimestampedProfile] = [:]
|
private var profiles: [String: TimestampedProfile] = [:]
|
||||||
var validated: [String: NIP05] = [:]
|
private var validated: [String: NIP05] = [:]
|
||||||
var nip05_pubkey: [String: String] = [:]
|
var nip05_pubkey: [String: String] = [:]
|
||||||
var zappers: [String: String] = [:]
|
var zappers: [String: String] = [:]
|
||||||
|
|
||||||
@ -31,11 +35,19 @@ class Profiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func is_validated(_ pk: String) -> NIP05? {
|
func is_validated(_ pk: String) -> NIP05? {
|
||||||
validated[pk]
|
validated_queue.sync {
|
||||||
|
validated[pk]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func set_validated(_ pk: String, nip05: NIP05?) {
|
||||||
|
validated_queue.async(flags: .barrier) {
|
||||||
|
self.validated[pk] = nip05
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func enumerated() -> EnumeratedSequence<[String: TimestampedProfile]> {
|
func enumerated() -> EnumeratedSequence<[String: TimestampedProfile]> {
|
||||||
return queue.sync {
|
return profiles_queue.sync {
|
||||||
return profiles.enumerated()
|
return profiles.enumerated()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +57,7 @@ class Profiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func add(id: String, profile: TimestampedProfile) {
|
func add(id: String, profile: TimestampedProfile) {
|
||||||
queue.async(flags: .barrier) {
|
profiles_queue.async(flags: .barrier) {
|
||||||
let old_timestamped_profile = self.profiles[id]
|
let old_timestamped_profile = self.profiles[id]
|
||||||
self.profiles[id] = profile
|
self.profiles[id] = profile
|
||||||
self.user_search_cache.updateProfile(id: id, profiles: self, oldProfile: old_timestamped_profile?.profile, newProfile: profile.profile)
|
self.user_search_cache.updateProfile(id: id, profiles: self, oldProfile: old_timestamped_profile?.profile, newProfile: profile.profile)
|
||||||
@ -62,14 +74,14 @@ class Profiles {
|
|||||||
|
|
||||||
func lookup(id: String) -> Profile? {
|
func lookup(id: String) -> Profile? {
|
||||||
var profile: Profile?
|
var profile: Profile?
|
||||||
queue.sync {
|
profiles_queue.sync {
|
||||||
profile = profiles[id]?.profile
|
profile = profiles[id]?.profile
|
||||||
}
|
}
|
||||||
return profile ?? database.get(id: id)
|
return profile ?? database.get(id: id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup_with_timestamp(id: String) -> TimestampedProfile? {
|
func lookup_with_timestamp(id: String) -> TimestampedProfile? {
|
||||||
queue.sync {
|
profiles_queue.sync {
|
||||||
return profiles[id]
|
return profiles[id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +89,7 @@ class Profiles {
|
|||||||
func has_fresh_profile(id: String) -> Bool {
|
func has_fresh_profile(id: String) -> Bool {
|
||||||
// check memory first
|
// check memory first
|
||||||
var profile: Profile?
|
var profile: Profile?
|
||||||
queue.sync {
|
profiles_queue.sync {
|
||||||
profile = profiles[id]?.profile
|
profile = profiles[id]?.profile
|
||||||
}
|
}
|
||||||
if profile != nil {
|
if profile != nil {
|
||||||
|
@ -194,7 +194,6 @@ func search_profiles(profiles: Profiles, search: String) -> [SearchedUser] {
|
|||||||
let matched_pubkeys = profiles.user_search_cache.search(key: new)
|
let matched_pubkeys = profiles.user_search_cache.search(key: new)
|
||||||
|
|
||||||
return matched_pubkeys
|
return matched_pubkeys
|
||||||
.map { ($0, profiles.lookup(id: $0)) }
|
.map { SearchedUser(profile: profiles.lookup(id: $0), pubkey: $0) }
|
||||||
.filter { $1 != nil }
|
.filter { $0.profile != nil }
|
||||||
.map { SearchedUser(profile: $1, pubkey: $0) }
|
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,9 @@ final class UserSearchCacheTests: XCTestCase {
|
|||||||
|
|
||||||
if let keypair {
|
if let keypair {
|
||||||
let pubkey = keypair.pubkey
|
let pubkey = keypair.pubkey
|
||||||
|
let validatedNip05 = try XCTUnwrap(NIP05.parse(nip05))
|
||||||
|
|
||||||
damusState.profiles.validated[pubkey] = NIP05.parse(nip05)
|
damusState.profiles.set_validated(pubkey, nip05: validatedNip05)
|
||||||
|
|
||||||
let profile = Profile(name: "tyiu", display_name: "Terry Yiu", about: nil, picture: nil, banner: nil, website: nil, lud06: nil, lud16: nil, nip05: nip05, damus_donation: nil)
|
let profile = Profile(name: "tyiu", display_name: "Terry Yiu", about: nil, picture: nil, banner: nil, website: nil, lud06: nil, lud16: nil, nip05: nip05, damus_donation: nil)
|
||||||
let timestampedProfile = TimestampedProfile(profile: profile, timestamp: 0, event: test_event)
|
let timestampedProfile = TimestampedProfile(profile: profile, timestamp: 0, event: test_event)
|
||||||
@ -50,7 +51,9 @@ final class UserSearchCacheTests: XCTestCase {
|
|||||||
let keypair = try XCTUnwrap(keypair)
|
let keypair = try XCTUnwrap(keypair)
|
||||||
|
|
||||||
let newNip05 = "_@other.xyz"
|
let newNip05 = "_@other.xyz"
|
||||||
damusState.profiles.validated[keypair.pubkey] = NIP05.parse(newNip05)
|
let validatedNewNip05 = try XCTUnwrap(NIP05.parse(newNip05))
|
||||||
|
|
||||||
|
damusState.profiles.set_validated(keypair.pubkey, nip05: NIP05.parse(newNip05))
|
||||||
|
|
||||||
let newProfile = Profile(name: "whoami", display_name: "T-DAWG", about: nil, picture: nil, banner: nil, website: nil, lud06: nil, lud16: nil, nip05: newNip05, damus_donation: nil)
|
let newProfile = Profile(name: "whoami", display_name: "T-DAWG", about: nil, picture: nil, banner: nil, website: nil, lud06: nil, lud16: nil, nip05: newNip05, damus_donation: nil)
|
||||||
let newTimestampedProfile = TimestampedProfile(profile: newProfile, timestamp: 1000, event: test_event)
|
let newTimestampedProfile = TimestampedProfile(profile: newProfile, timestamp: 1000, event: test_event)
|
||||||
|
Loading…
Reference in New Issue
Block a user