Profiles.swift (3190B)
1 // 2 // Profiles.swift 3 // damus 4 // 5 // Created by William Casarin on 2022-04-17. 6 // 7 8 import Foundation 9 10 class ValidationModel: ObservableObject { 11 @Published var validated: NIP05? 12 13 init() { 14 self.validated = nil 15 } 16 } 17 18 class ProfileData { 19 var status: UserStatusModel 20 var validation_model: ValidationModel 21 var zapper: Pubkey? 22 23 init() { 24 status = .init() 25 validation_model = .init() 26 zapper = nil 27 } 28 } 29 30 class Profiles { 31 private var ndb: Ndb 32 33 static let db_freshness_threshold: TimeInterval = 24 * 60 * 8 34 35 @MainActor 36 private var profiles: [Pubkey: ProfileData] = [:] 37 38 @MainActor 39 var nip05_pubkey: [String: Pubkey] = [:] 40 41 init(ndb: Ndb) { 42 self.ndb = ndb 43 } 44 45 @MainActor 46 func is_validated(_ pk: Pubkey) -> NIP05? { 47 self.profile_data(pk).validation_model.validated 48 } 49 50 @MainActor 51 func invalidate_nip05(_ pk: Pubkey) { 52 self.profile_data(pk).validation_model.validated = nil 53 } 54 55 @MainActor 56 func set_validated(_ pk: Pubkey, nip05: NIP05?) { 57 self.profile_data(pk).validation_model.validated = nip05 58 } 59 60 @MainActor 61 func profile_data(_ pubkey: Pubkey) -> ProfileData { 62 guard let data = profiles[pubkey] else { 63 let data = ProfileData() 64 profiles[pubkey] = data 65 return data 66 } 67 68 return data 69 } 70 71 @MainActor 72 func lookup_zapper(pubkey: Pubkey) -> Pubkey? { 73 profile_data(pubkey).zapper 74 } 75 76 func lookup_with_timestamp(_ pubkey: Pubkey) -> NdbTxn<ProfileRecord?>? { 77 ndb.lookup_profile(pubkey) 78 } 79 80 func lookup_by_key(key: ProfileKey) -> NdbTxn<ProfileRecord?>? { 81 ndb.lookup_profile_by_key(key: key) 82 } 83 84 func search<Y>(_ query: String, limit: Int, txn: NdbTxn<Y>) -> [Pubkey] { 85 ndb.search_profile(query, limit: limit, txn: txn) 86 } 87 88 func lookup(id: Pubkey, txn_name: String? = nil) -> NdbTxn<Profile?>? { 89 guard let txn = ndb.lookup_profile(id, txn_name: txn_name) else { 90 return nil 91 } 92 return txn.map({ pr in pr?.profile }) 93 } 94 95 func lookup_key_by_pubkey(_ pubkey: Pubkey) -> ProfileKey? { 96 ndb.lookup_profile_key(pubkey) 97 } 98 99 func has_fresh_profile<Y>(id: Pubkey, txn: NdbTxn<Y>) -> Bool { 100 guard let fetched_at = ndb.read_profile_last_fetched(txn: txn, pubkey: id) 101 else { 102 return false 103 } 104 105 // In situations where a batch of profiles was fetched all at once, 106 // this will reduce the herding of the profile requests 107 let fuzz = Double.random(in: -60...60) 108 let threshold = Profiles.db_freshness_threshold + fuzz 109 let fetch_date = Date(timeIntervalSince1970: Double(fetched_at)) 110 111 let since = Date.now.timeIntervalSince(fetch_date) 112 let fresh = since < threshold 113 114 //print("fresh = \(fresh): fetch_date \(since) < threshold \(threshold) \(id)") 115 116 return fresh 117 } 118 } 119 120 121 @MainActor 122 func invalidate_zapper_cache(pubkey: Pubkey, profiles: Profiles, lnurl: LNUrls) { 123 profiles.profile_data(pubkey).zapper = nil 124 lnurl.endpoints.removeValue(forKey: pubkey) 125 }