mirror of https://github.com/lukechilds/damus.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
6.1 KiB
214 lines
6.1 KiB
//
|
|
// ThreadModel.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2022-04-19.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
enum InitialEvent {
|
|
case event(NostrEvent)
|
|
case event_id(String)
|
|
|
|
var is_event_id: String? {
|
|
if case .event_id(let evid) = self {
|
|
return evid
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var id: String {
|
|
switch self {
|
|
case .event(let ev):
|
|
return ev.id
|
|
case .event_id(let evid):
|
|
return evid
|
|
}
|
|
}
|
|
}
|
|
|
|
/// manages the lifetime of a thread
|
|
class ThreadModel: ObservableObject {
|
|
@Published var initial_event: InitialEvent
|
|
@Published var events: [NostrEvent] = []
|
|
@Published var event_map: [String: Int] = [:]
|
|
@Published var loading: Bool = false
|
|
|
|
var replies: ReplyMap = ReplyMap()
|
|
|
|
var event: NostrEvent? {
|
|
switch initial_event {
|
|
case .event(let ev):
|
|
return ev
|
|
case .event_id(let evid):
|
|
for event in events {
|
|
if event.id == evid {
|
|
return event
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
let damus_state: DamusState
|
|
|
|
let profiles_subid = UUID().description
|
|
var base_subid = UUID().description
|
|
|
|
init(evid: String, damus_state: DamusState) {
|
|
self.damus_state = damus_state
|
|
self.initial_event = .event_id(evid)
|
|
}
|
|
|
|
init(event: NostrEvent, damus_state: DamusState) {
|
|
self.damus_state = damus_state
|
|
self.initial_event = .event(event)
|
|
}
|
|
|
|
func unsubscribe() {
|
|
self.damus_state.pool.unsubscribe(sub_id: base_subid)
|
|
print("unsubscribing from thread \(initial_event.id) with sub_id \(base_subid)")
|
|
}
|
|
|
|
func reset_events() {
|
|
self.events.removeAll()
|
|
self.event_map.removeAll()
|
|
self.replies.replies.removeAll()
|
|
}
|
|
|
|
func should_resubscribe(_ ev_b: NostrEvent) -> Bool {
|
|
if self.events.count == 0 {
|
|
return true
|
|
}
|
|
|
|
if ev_b.is_root_event() {
|
|
return false
|
|
}
|
|
|
|
// rough heuristic to save us from resubscribing all the time
|
|
//return ev_b.count_ids() != self.event.count_ids()
|
|
return true
|
|
}
|
|
|
|
func set_active_event(_ ev: NostrEvent, privkey: String?) {
|
|
if should_resubscribe(ev) {
|
|
unsubscribe()
|
|
self.initial_event = .event(ev)
|
|
subscribe()
|
|
} else {
|
|
self.initial_event = .event(ev)
|
|
if events.count == 0 {
|
|
add_event(ev, privkey: privkey)
|
|
}
|
|
}
|
|
}
|
|
|
|
func subscribe() {
|
|
var ref_events = NostrFilter()
|
|
var events_filter = NostrFilter()
|
|
//var likes_filter = NostrFilter.filter_kinds(7])
|
|
|
|
// TODO: add referenced relays
|
|
switch self.initial_event {
|
|
case .event(let ev):
|
|
ref_events.referenced_ids = ev.referenced_ids.map { $0.ref_id }
|
|
ref_events.referenced_ids?.append(ev.id)
|
|
ref_events.limit = 50
|
|
events_filter.ids = ref_events.referenced_ids!
|
|
events_filter.limit = 100
|
|
events_filter.ids?.append(ev.id)
|
|
case .event_id(let evid):
|
|
ref_events.referenced_ids = [evid]
|
|
ref_events.limit = 50
|
|
events_filter.ids = [evid]
|
|
events_filter.limit = 100
|
|
}
|
|
|
|
//likes_filter.ids = ref_events.referenced_ids!
|
|
|
|
print("subscribing to thread \(initial_event.id) with sub_id \(base_subid)")
|
|
damus_state.pool.register_handler(sub_id: base_subid, handler: handle_event)
|
|
loading = true
|
|
damus_state.pool.send(.subscribe(.init(filters: [ref_events, events_filter], sub_id: base_subid)))
|
|
}
|
|
|
|
func lookup(_ event_id: String) -> NostrEvent? {
|
|
if let i = event_map[event_id] {
|
|
return events[i]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func add_event(_ ev: NostrEvent, privkey: String?) {
|
|
guard ev.should_show_event else {
|
|
return
|
|
}
|
|
|
|
if event_map[ev.id] != nil {
|
|
return
|
|
}
|
|
|
|
for reply in ev.direct_replies(privkey) {
|
|
self.replies.add(id: ev.id, reply_id: reply.ref_id)
|
|
}
|
|
|
|
if insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { $0.created_at < $1.created_at }) {
|
|
objectWillChange.send()
|
|
}
|
|
//self.events.append(ev)
|
|
//self.events = self.events.sorted { $0.created_at < $1.created_at }
|
|
|
|
var i: Int = 0
|
|
for ev in events {
|
|
self.event_map[ev.id] = i
|
|
i += 1
|
|
}
|
|
|
|
if let evid = self.initial_event.is_event_id {
|
|
if ev.id == evid {
|
|
// this should trigger a resubscribe...
|
|
set_active_event(ev, privkey: privkey)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func handle_channel_meta(_ ev: NostrEvent) {
|
|
guard let meta: ChatroomMetadata = decode_json(ev.content) else {
|
|
return
|
|
}
|
|
|
|
notify(.chatroom_meta, meta)
|
|
}
|
|
|
|
func handle_event(relay_id: String, ev: NostrConnectionEvent) {
|
|
|
|
let (sub_id, done) = handle_subid_event(pool: damus_state.pool, relay_id: relay_id, ev: ev) { sid, ev in
|
|
guard sid == base_subid || sid == profiles_subid else {
|
|
return
|
|
}
|
|
|
|
if ev.known_kind == .metadata {
|
|
process_metadata_event(profiles: damus_state.profiles, ev: ev)
|
|
} else if ev.is_textlike {
|
|
self.add_event(ev, privkey: self.damus_state.keypair.privkey)
|
|
} else if ev.known_kind == .channel_meta || ev.known_kind == .channel_create {
|
|
handle_channel_meta(ev)
|
|
}
|
|
}
|
|
|
|
guard done && (sub_id == base_subid || sub_id == profiles_subid) else {
|
|
return
|
|
}
|
|
|
|
if (events.contains { ev in ev.id == initial_event.id }) {
|
|
loading = false
|
|
}
|
|
|
|
if sub_id == self.base_subid {
|
|
load_profiles(profiles_subid: self.profiles_subid, relay_id: relay_id, events: events, damus_state: damus_state)
|
|
}
|
|
}
|
|
|
|
}
|
|
|