damus

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

ThreadModel.swift (4723B)


      1 //
      2 //  ThreadModel.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2022-04-19.
      6 //
      7 
      8 import Foundation
      9 
     10 /// manages the lifetime of a thread
     11 class ThreadModel: ObservableObject {
     12     @Published var event: NostrEvent
     13     let original_event: NostrEvent
     14     var event_map: Set<NostrEvent>
     15     
     16     init(event: NostrEvent, damus_state: DamusState) {
     17         self.damus_state = damus_state
     18         self.event_map = Set()
     19         self.event = event
     20         self.original_event = event
     21         add_event(event, keypair: damus_state.keypair)
     22     }
     23     
     24     var is_original: Bool {
     25         return original_event.id == event.id
     26     }
     27     
     28     let damus_state: DamusState
     29     
     30     let profiles_subid = UUID().description
     31     let base_subid = UUID().description
     32     let meta_subid = UUID().description
     33     
     34     var subids: [String] {
     35         return [profiles_subid, base_subid, meta_subid]
     36     }
     37     
     38     func unsubscribe() {
     39         self.damus_state.pool.remove_handler(sub_id: base_subid)
     40         self.damus_state.pool.remove_handler(sub_id: meta_subid)
     41         self.damus_state.pool.remove_handler(sub_id: profiles_subid)
     42         self.damus_state.pool.unsubscribe(sub_id: base_subid)
     43         self.damus_state.pool.unsubscribe(sub_id: meta_subid)
     44         self.damus_state.pool.unsubscribe(sub_id: profiles_subid)
     45         print("unsubscribing from thread \(event.id) with sub_id \(base_subid)")
     46     }
     47     
     48     @discardableResult
     49     func set_active_event(_ ev: NostrEvent, keypair: Keypair) -> Bool {
     50         self.event = ev
     51         add_event(ev, keypair: keypair)
     52 
     53         //self.objectWillChange.send()
     54         return false
     55     }
     56     
     57     func subscribe() {
     58         var meta_events = NostrFilter()
     59         var quote_events = NostrFilter()
     60         var event_filter = NostrFilter()
     61         var ref_events = NostrFilter()
     62 
     63         let thread_id = event.thread_id(keypair: .empty)
     64 
     65         ref_events.referenced_ids = [thread_id, event.id]
     66         ref_events.kinds = [.text]
     67         ref_events.limit = 1000
     68         
     69         event_filter.ids = [thread_id, event.id]
     70         
     71         meta_events.referenced_ids = [event.id]
     72 
     73         var kinds: [NostrKind] = [.zap, .text, .boost]
     74         if !damus_state.settings.onlyzaps_mode {
     75             kinds.append(.like)
     76         }
     77         meta_events.kinds = kinds
     78         meta_events.limit = 1000
     79 
     80         quote_events.kinds = [.text]
     81         quote_events.quotes = [event.id]
     82         quote_events.limit = 1000
     83 
     84         let base_filters = [event_filter, ref_events]
     85         let meta_filters = [meta_events, quote_events]
     86 
     87         print("subscribing to thread \(event.id) with sub_id \(base_subid)")
     88         damus_state.pool.subscribe(sub_id: base_subid, filters: base_filters, handler: handle_event)
     89         damus_state.pool.subscribe(sub_id: meta_subid, filters: meta_filters, handler: handle_event)
     90     }
     91     
     92     func add_event(_ ev: NostrEvent, keypair: Keypair) {
     93         if event_map.contains(ev) {
     94             return
     95         }
     96         
     97         damus_state.events.upsert(ev)
     98         damus_state.replies.count_replies(ev, keypair: keypair)
     99         damus_state.events.add_replies(ev: ev, keypair: keypair)
    100 
    101         event_map.insert(ev)
    102         objectWillChange.send()
    103     }
    104 
    105     @MainActor
    106     func handle_event(relay_id: RelayURL, ev: NostrConnectionEvent) {
    107 
    108         let (sub_id, done) = handle_subid_event(pool: damus_state.pool, relay_id: relay_id, ev: ev) { sid, ev in
    109             guard subids.contains(sid) else {
    110                 return
    111             }
    112             
    113             if ev.known_kind == .zap {
    114                 process_zap_event(state: damus_state, ev: ev) { zap in
    115                     
    116                 }
    117             } else if ev.is_textlike {
    118                 // handle thread quote reposts, we just count them instead of
    119                 // adding them to the thread
    120                 if let target = ev.is_quote_repost, target == self.event.id {
    121                     //let _ = self.damus_state.quote_reposts.add_event(ev, target: target)
    122                 } else {
    123                     self.add_event(ev, keypair: damus_state.keypair)
    124                 }
    125             }
    126         }
    127         
    128         guard done, let sub_id, subids.contains(sub_id) else {
    129             return
    130         }
    131         
    132         if sub_id == self.base_subid {
    133             guard let txn = NdbTxn(ndb: damus_state.ndb) else { return }
    134             load_profiles(context: "thread", profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(Array(event_map)), damus_state: damus_state, txn: txn)
    135         }
    136     }
    137 
    138 }
    139 
    140 
    141 func get_top_zap(events: EventCache, evid: NoteId) -> Zapping? {
    142     return events.get_cache_data(evid).zaps_model.zaps.first(where: { zap in
    143         !zap.request.marked_hidden
    144     })
    145 }