damus

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

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 }