likes, mention parsing, lots of stuff

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2022-05-04 16:26:10 -07:00
parent 403fa74f8d
commit f42bc2e91e
25 changed files with 608 additions and 118 deletions

View File

@@ -46,7 +46,7 @@ struct ContentView: View {
@State var profiles: Profiles = Profiles()
@State var friends: [String: ()] = [:]
@State var loading: Bool = true
@State var pool: RelayPool? = nil
@State var damus: DamusState? = nil
@State var selected_timeline: Timeline? = .home
@State var is_thread_open: Bool = false
@State var is_profile_open: Bool = false
@@ -135,15 +135,15 @@ struct ContentView: View {
var PostingTimelineView: some View {
ZStack {
if let pool = self.pool {
TimelineView(events: $friend_events, pool: pool)
if let damus = self.damus {
TimelineView(events: $friend_events, damus: damus)
.environmentObject(profiles)
}
PostButtonContainer
}
}
func MainContent(pool: RelayPool) -> some View {
func MainContent(damus: DamusState) -> some View {
NavigationView {
VStack {
switch selected_timeline {
@@ -154,13 +154,13 @@ struct ContentView: View {
}
case .notifications:
TimelineView(events: $notifications, pool: pool)
TimelineView(events: $notifications, damus: damus)
.environmentObject(profiles)
.navigationTitle("Notifications")
case .global:
TimelineView(events: $events, pool: pool)
TimelineView(events: $events, damus: damus)
.environmentObject(profiles)
.navigationTitle("Global")
case .none:
@@ -174,9 +174,9 @@ struct ContentView: View {
var body: some View {
VStack {
if let pool = self.pool {
if let damus = self.damus {
ZStack {
MainContent(pool: pool)
MainContent(damus: damus)
.padding([.bottom], -8.0)
LoadingContainer
@@ -193,14 +193,14 @@ struct ContentView: View {
case .post:
PostView(references: [])
case .reply(let event):
ReplyView(replying_to: event, pool: pool!)
ReplyView(replying_to: event, damus: damus!)
.environmentObject(profiles)
}
}
.onReceive(handle_notify(.boost)) { notif in
let ev = notif.object as! NostrEvent
let boost = make_boost_event(ev, privkey: privkey, pubkey: pubkey)
self.pool?.send(.event(boost))
self.damus?.pool.send(.event(boost))
}
.onReceive(handle_notify(.open_thread)) { obj in
//let ev = obj.object as! NostrEvent
@@ -211,9 +211,18 @@ struct ContentView: View {
let ev = notif.object as! NostrEvent
self.active_sheet = .reply(ev)
}
.onReceive(handle_notify(.like)) { like in
let ev = like.object as! NostrEvent
guard let like_ev = make_like_event(pubkey: pubkey, liked: ev) else {
return
}
like_ev.calculate_id()
like_ev.sign(privkey: privkey)
self.damus?.pool.send(.event(like_ev))
}
.onReceive(handle_notify(.broadcast_event)) { obj in
let ev = obj.object as! NostrEvent
self.pool?.send(.event(ev))
self.damus?.pool.send(.event(ev))
}
.onReceive(handle_notify(.post)) { obj in
let post_res = obj.object as! NostrPostResult
@@ -221,15 +230,15 @@ struct ContentView: View {
case .post(let post):
print("post \(post.content)")
let new_ev = post.to_event(privkey: privkey, pubkey: pubkey)
self.pool?.send(.event(new_ev))
self.damus?.pool.send(.event(new_ev))
case .cancel:
active_sheet = nil
print("post cancelled")
}
}
.onReceive(timer) { n in
self.pool?.connect_to_disconnected()
self.loading = (self.pool?.num_connecting ?? 0) != 0
self.damus?.pool.connect_to_disconnected()
self.loading = (self.damus?.pool.num_connecting ?? 0) != 0
}
}
@@ -292,7 +301,9 @@ struct ContentView: View {
pool.register_handler(sub_id: sub_id, handler: handle_event)
self.pool = pool
self.damus = DamusState(pool: pool, pubkey: pubkey,
likes: EventCounter(our_pubkey: pubkey),
boosts: EventCounter(our_pubkey: pubkey))
pool.connect()
}
@@ -306,7 +317,28 @@ struct ContentView: View {
}
}
}
func handle_boost_event(_ ev: NostrEvent) {
damus!.boosts.add_event(ev)
}
func handle_like_event(_ ev: NostrEvent) {
guard let e = ev.last_refid() else {
// no id ref? invalid like event
return
}
// CHECK SIGS ON THESE
switch damus!.likes.add_event(ev) {
case .user_already_liked:
break
case .success(let n):
let liked = Liked(like: ev, id: e.ref_id, total: n)
notify(.liked, liked)
}
}
func handle_metadata_event(_ ev: NostrEvent) {
guard let profile: Profile = decode_data(Data(ev.content.utf8)) else {
return
@@ -335,11 +367,15 @@ struct ContentView: View {
func send_filters(relay_id: String) {
// TODO: since times should be based on events from a specific relay
// perhaps we could mark this in the relay pool somehow
let last_text_event = get_last_event_of_kind(relay_id: relay_id, kind: NostrKind.text.rawValue)
let since = get_since_time(last_event: last_text_event)
var since_filter = NostrFilter.filter_text
var since_filter = NostrFilter.filter_kinds([1,5,6])
since_filter.since = since
let last_like_event = get_last_event_of_kind(relay_id: relay_id, kind: 7)
var like_filter = NostrFilter.filter_kinds([7])
like_filter.since = get_since_time(last_event: last_like_event)
//like_filter.ids = get_like_pow()
let last_metadata_event = get_last_event_of_kind(relay_id: relay_id, kind: NostrKind.metadata.rawValue)
var profile_filter = NostrFilter.filter_profiles
@@ -355,9 +391,9 @@ struct ContentView: View {
var contacts_filter = NostrFilter.filter_contacts
contacts_filter.authors = [self.pubkey]
let filters = [since_filter, profile_filter, contacts_filter]
let filters = [since_filter, profile_filter, contacts_filter, like_filter]
print("connected to \(relay_id), refreshing from \(since)")
self.pool?.send(.subscribe(.init(filters: filters, sub_id: sub_id)), to: [relay_id])
self.damus?.pool.send(.subscribe(.init(filters: filters, sub_id: sub_id)), to: [relay_id])
//self.pool?.send(.subscribe(.init(filters: [notification_filter], sub_id: "notifications")))
}
@@ -382,32 +418,42 @@ struct ContentView: View {
self.friend_events = self.friend_events.sorted { $0.created_at > $1.created_at }
}
func handle_text_event(_ ev: NostrEvent) {
if should_hide_event(ev) {
return
}
self.events.append(ev)
self.events = self.events.sorted { $0.created_at > $1.created_at }
handle_friend_event(ev)
if is_notification(ev: ev, pubkey: pubkey) {
handle_notification(ev: ev)
}
}
func process_event(relay_id: String, ev: NostrEvent) {
if has_events[ev.id] == nil {
has_events[ev.id] = ()
let last_k = get_last_event_of_kind(relay_id: relay_id, kind: ev.kind)
if last_k == nil || ev.created_at > last_k!.created_at {
last_event_of_kind[relay_id]?[ev.kind] = ev
}
if ev.kind == 1 {
if !should_hide_event(ev) {
self.events.append(ev)
self.events = self.events.sorted { $0.created_at > $1.created_at }
handle_friend_event(ev)
if is_notification(ev: ev, pubkey: pubkey) {
handle_notification(ev: ev)
}
}
} else if ev.kind == 0 {
handle_metadata_event(ev)
} else if ev.kind == 3 {
handle_contact_event(ev)
if ev.pubkey == pubkey {
process_friend_events()
}
if has_events[ev.id] != nil {
return
}
has_events[ev.id] = ()
let last_k = get_last_event_of_kind(relay_id: relay_id, kind: ev.kind)
if last_k == nil || ev.created_at > last_k!.created_at {
last_event_of_kind[relay_id]?[ev.kind] = ev
}
if ev.kind == 1 {
handle_text_event(ev)
} else if ev.kind == 0 {
handle_metadata_event(ev)
} else if ev.kind == 7 {
handle_like_event(ev)
} else if ev.kind == 3 {
handle_contact_event(ev)
if ev.pubkey == pubkey {
process_friend_events()
}
}
}
@@ -436,27 +482,29 @@ struct ContentView: View {
case .error(let merr):
let desc = merr.debugDescription
if desc.contains("Software caused connection abort") {
self.pool?.reconnect(to: [relay_id])
self.damus?.pool.reconnect(to: [relay_id])
}
case .disconnected: fallthrough
case .cancelled:
self.pool?.reconnect(to: [relay_id])
self.damus?.pool.reconnect(to: [relay_id])
case .reconnectSuggested(let t):
if t {
self.pool?.reconnect(to: [relay_id])
self.damus?.pool.reconnect(to: [relay_id])
}
default:
break
}
self.loading = (self.pool?.num_connecting ?? 0) != 0
self.loading = (self.damus?.pool.num_connecting ?? 0) != 0
print("ws_event \(ev)")
case .nostr_event(let ev):
switch ev {
case .event(let sub_id, let ev):
if sub_id != self.sub_id {
// globally handle likes
let always_process = ev.known_kind == .like || ev.known_kind == .contacts || ev.known_kind == .metadata
if !always_process && sub_id != self.sub_id {
// TODO: other views like threads might have their own sub ids, so ignore those events... or should we?
return
}
@@ -593,3 +641,8 @@ func make_boost_event(_ ev: NostrEvent, privkey: String, pubkey: String) -> Nost
boost.sign(privkey: privkey)
return boost
}
func get_like_pow() -> [String] {
return ["00000"] // 20 bits
}