damus

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

commit 593d0e2abe61a5b2208214727e1747ba7ecf7888
parent 2f8aa29e92f9c5077936bf61b64a12d09ec0bd30
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 25 Jul 2023 16:22:25 -0700

ndb: sync up a few remaining NdbNote tag differences

Diffstat:
Mdamus/ContentParsing.swift | 14++++++++++----
Mdamus/Models/Contacts.swift | 22+++++++++++-----------
Mdamus/Models/EventsModel.swift | 2+-
Mdamus/Models/NotificationsModel.swift | 4++--
Mdamus/Models/ProfileModel.swift | 13++++++-------
Mdamus/Nostr/NostrEvent.swift | 26+++++++++++++++-----------
Mdamus/Nostr/ReferencedId.swift | 21++++++++++++++++++---
Mdamus/Util/Images/ImageMetadata.swift | 4++--
Mdamus/Util/WalletConnect.swift | 4++--
Mdamus/Util/Zap.swift | 18+++++-------------
Mnostrdb/NdbNote.swift | 2+-
Mnostrdb/NdbTagElem.swift | 13+++++++++++++
Mnostrdb/NdbTagIterator.swift | 8++++++--
Mnostrdb/Test/NdbTests.swift | 2+-
14 files changed, 93 insertions(+), 60 deletions(-)

diff --git a/damus/ContentParsing.swift b/damus/ContentParsing.swift @@ -8,10 +8,15 @@ import Foundation func tag_to_refid_ndb(_ tag: TagSequence) -> ReferencedId? { - guard let ref_id = tag[1]?.string(), - let key = tag[0]?.string() else { return nil } + guard tag.count >= 2 else { return nil } - let relay_id = tag[2]?.string() + let key = tag[0].string() + let ref_id = tag[1].string() + + var relay_id: String? = nil + if tag.count >= 3 { + relay_id = tag[2].string() + } return ReferencedId(ref_id: ref_id, relay_id: relay_id, key: key) } @@ -123,7 +128,8 @@ func interp_event_refs_with_mentions_ndb(tags: TagsSequence, mention_indices: Se var i: Int = 0 for tag in tags { - if tag.count >= 2, let t = tag[0], t.matches_char("e"), + if tag.count >= 2, + tag[0].matches_char("e"), let ref = tag_to_refid_ndb(tag) { if mention_indices.contains(i) { diff --git a/damus/Models/Contacts.swift b/damus/Models/Contacts.swift @@ -147,22 +147,22 @@ func unfollow_reference(postbox: PostBox, our_contacts: NostrEvent?, keypair: Fu } func unfollow_reference_event(our_contacts: NostrEvent, keypair: FullKeypair, unfollow: ReferencedId) -> NostrEvent? { - let tags = our_contacts.tags.filter { tag in - if let key = tag[safe: 0], - let ref = tag[safe: 1], + let tags = our_contacts.tags.reduce(into: [[String]]()) { ts, tag in + if tag.count >= 2, let fst = unfollow.key.first, let afst = AsciiCharacter(fst), - key.matches_char(afst), - ref.string() == unfollow.ref_id + tag[0].matches_char(afst), + tag[1].matches_str(unfollow.ref_id) { - return false + return } - return true + + ts.append(tag.strings()) } - + let kind = NostrKind.contacts.rawValue - return NostrEvent(content: our_contacts.content, keypair: keypair.to_keypair(), kind: kind, tags: tags) + return NostrEvent(content: our_contacts.content, keypair: keypair.to_keypair(), kind: kind, tags: Array(tags)) } func follow_user_event(our_contacts: NostrEvent?, keypair: FullKeypair, follow: ReferencedId) -> NostrEvent? { @@ -193,7 +193,7 @@ func remove_relay(ev: NostrEvent, current_relays: [RelayDescriptor], keypair: Fu return nil } - return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 3, tags: ev.tags) + return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 3, tags: ev.tags.strings()) } func add_relay(ev: NostrEvent, keypair: FullKeypair, current_relays: [RelayDescriptor], relay: String, info: RelayInfo) -> NostrEvent? { @@ -209,7 +209,7 @@ func add_relay(ev: NostrEvent, keypair: FullKeypair, current_relays: [RelayDescr return nil } - return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 3, tags: ev.tags) + return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 3, tags: ev.tags.strings()) } func ensure_relay_info(relays: [RelayDescriptor], content: String) -> [String: RelayInfo] { diff --git a/damus/Models/EventsModel.swift b/damus/Models/EventsModel.swift @@ -45,7 +45,7 @@ class EventsModel: ObservableObject { return } - guard last_etag(tags: ev.tags) == target else { + guard ev.referenced_ids.last?.ref_id.string() == target else { return } diff --git a/damus/Models/NotificationsModel.swift b/damus/Models/NotificationsModel.swift @@ -214,11 +214,11 @@ class NotificationsModel: ObservableObject, ScrollQueue { let id = ref_id.id - if let evgrp = self.reactions[id] { + if let evgrp = self.reactions[id.string()] { return evgrp.insert(ev) } else { let evgrp = EventGroup() - self.reactions[id] = evgrp + self.reactions[id.string()] = evgrp return evgrp.insert(ev) } } diff --git a/damus/Models/ProfileModel.swift b/damus/Models/ProfileModel.swift @@ -35,13 +35,12 @@ class ProfileModel: ObservableObject, Equatable { } for tag in contacts.tags { - guard tag.count >= 2 && tag[0].matches_char("p") else { + guard tag.count >= 2, + tag[0].matches_char("p"), + tag[1].matches_str(pubkey) + else { continue } - - if tag[1] == pubkey { - return true - } } return false @@ -145,10 +144,10 @@ class ProfileModel: ObservableObject, Equatable { } -func count_pubkeys(_ tags: [[String]]) -> Int { +func count_pubkeys(_ tags: Tags) -> Int { var c: Int = 0 for tag in tags { - if tag.count >= 2 && tag[0] == "p" { + if tag.count >= 2 && tag[0].matches_char("p") { c += 1 } } diff --git a/damus/Nostr/NostrEvent.swift b/damus/Nostr/NostrEvent.swift @@ -21,6 +21,8 @@ enum ValidationResult: Decodable { } //typealias NostrEvent = NdbNote +//typealias Tags = TagsSequence +typealias Tags = [[String]] typealias NostrEvent = NostrEventOld let MAX_NOTE_SIZE: Int = 2 << 18 @@ -54,7 +56,7 @@ class NostrEventOld: Codable, Identifiable, CustomStringConvertible, Equatable, let id: String let content: String let sig: String - let tags: [[String]] + let tags: Tags //var boosted_by: String? @@ -88,6 +90,18 @@ class NostrEventOld: Codable, Identifiable, CustomStringConvertible, Equatable, hasher.combine(id) } + static func owned_from_json(json: String) -> NostrEvent? { + let decoder = JSONDecoder() + guard let dat = json.data(using: .utf8) else { + return nil + } + guard let ev = try? decoder.decode(NostrEvent.self, from: dat) else { + return nil + } + + return ev + } + init?(content: String, keypair: Keypair, kind: UInt32 = 1, tags: [[String]] = [], createdAt: UInt32 = UInt32(Date().timeIntervalSince1970)) { self.content = content @@ -937,16 +951,6 @@ func validate_event(ev: NostrEvent) -> ValidationResult { return ok ? .ok : .bad_sig } -func last_etag(tags: [[String]]) -> String? { - var e: String? = nil - for tag in tags { - if tag.count >= 2 && tag[0] == "e" { - e = tag[1] - } - } - return e -} - func first_eref_mention(ev: NostrEvent, privkey: String?) -> Mention? { let blocks = ev.blocks(privkey).blocks.filter { block in guard case .mention(let mention) = block else { diff --git a/damus/Nostr/ReferencedId.swift b/damus/Nostr/ReferencedId.swift @@ -29,9 +29,11 @@ struct References: Sequence, IteratorProtocol { mutating func next() -> Reference? { while let tag = tags_iter.next() { - guard let key = tag[0], key.count == 1, - let id = tag[1], tagref_should_be_id(key) - else { continue } + guard tag.count >= 2 else { continue } + let key = tag[0] + let id = tag[1] + + guard key.count == 1, tagref_should_be_id(id) else { continue } for c in key { guard let a = AsciiCharacter(c) else { break } @@ -64,12 +66,21 @@ struct References: Sequence, IteratorProtocol { } } +// TagsSequence transition helpers extension [[String]] { func strings() -> [[String]] { return self } } +// TagsSequence transition helpers +extension [String] { + func strings() -> [String] { + return self + } +} + +// NdbTagElem transition helpers extension String { func string() -> String { return self @@ -82,6 +93,10 @@ extension String { func matches_char(_ c: AsciiCharacter) -> Bool { return self.first == c.character } + + func matches_str(_ str: String) -> Bool { + return self == str + } } struct ReferencedId: Identifiable, Hashable, Equatable { diff --git a/damus/Util/Images/ImageMetadata.swift b/damus/Util/Images/ImageMetadata.swift @@ -170,8 +170,8 @@ func calculate_image_metadata(url: URL, img: UIImage, blurhash: String) -> Image func event_image_metadata(ev: NostrEvent) -> [ImageMetadata] { return ev.tags.reduce(into: [ImageMetadata]()) { meta, tag in - guard tag.count >= 2 && tag[0] == "imeta", - let data = ImageMetadata(tag: tag) else { + guard tag.count >= 2, tag[0].matches_str("imeta"), + let data = ImageMetadata(tag: tag.strings()) else { return } diff --git a/damus/Util/WalletConnect.swift b/damus/Util/WalletConnect.swift @@ -94,8 +94,8 @@ struct FullWalletResponse { return nil } - self.req_id = req_id.ref_id - + self.req_id = req_id.ref_id.string() + let ares = Task { guard let json = decrypt_dm(nwc.keypair.privkey, pubkey: nwc.pubkey, content: from.content, encoding: .base64), let resp: WalletResponse = decode_json(json) diff --git a/damus/Util/Zap.swift b/damus/Util/Zap.swift @@ -49,7 +49,7 @@ struct ZapRequest { init(ev: NostrEvent) { self.ev = ev - self.marked_hidden = ev.tags.first(where: { t in t.count > 0 && t[0] == "hidden" }) != nil + self.marked_hidden = ev.tags.first(where: { t in t.count > 0 && t[0].matches_str("hidden") }) != nil } } @@ -295,7 +295,7 @@ struct Zap { guard let desc = get_zap_description(zap_ev, inv_desc: zap_invoice.description) else { return nil } - + guard let zap_req = decode_nostr_event_json(desc) else { return nil } @@ -392,8 +392,8 @@ func decode_bolt11(_ s: String) -> Invoice? { func event_tag(_ ev: NostrEvent, name: String) -> String? { for tag in ev.tags { - if tag.count >= 2 && tag[0] == name { - return tag[1] + if tag.count >= 2 && tag[0].matches_str(name) { + return tag[1].string() } } @@ -401,15 +401,7 @@ func event_tag(_ ev: NostrEvent, name: String) -> String? { } func decode_nostr_event_json(_ desc: String) -> NostrEvent? { - let decoder = JSONDecoder() - guard let dat = desc.data(using: .utf8) else { - return nil - } - guard let ev = try? decoder.decode(NostrEvent.self, from: dat) else { - return nil - } - - return ev + return NostrEvent.owned_from_json(json: desc) } diff --git a/nostrdb/NdbNote.swift b/nostrdb/NdbNote.swift @@ -104,7 +104,7 @@ class NdbNote: Equatable, Hashable { static let max_note_size: Int = 2 << 18 - init?(content: String, keypair: Keypair, kind: Int = 1, tags: [[String]] = [], createdAt: UInt32 = UInt32(Date().timeIntervalSince1970)) { + init?(content: String, keypair: Keypair, kind: UInt32 = 1, tags: [[String]] = [], createdAt: UInt32 = UInt32(Date().timeIntervalSince1970)) { var builder = ndb_builder() let buflen = MAX_NOTE_SIZE diff --git a/nostrdb/NdbTagElem.swift b/nostrdb/NdbTagElem.swift @@ -83,6 +83,19 @@ struct NdbTagElem: Sequence, Hashable { return str.str[0] == c.cchar && str.str[1] == 0 } + func matches_str(_ s: String) -> Bool { + if str.flag == NDB_PACKED_ID, + s.utf8.count == 64, + var decoded = hex_decode(s), decoded.count == 32 + { + return memcmp(&decoded, str.id, 32) == 0 + } + + let len = strlen(str.str) + guard len == s.utf8.count else { return false } + return s.withCString { cstr in memcmp(str.str, cstr, len) == 0 } + } + var ndbstr: ndb_str { return ndb_tag_str(note.note, tag, index) } diff --git a/nostrdb/NdbTagIterator.swift b/nostrdb/NdbTagIterator.swift @@ -15,8 +15,12 @@ struct TagSequence: Sequence { tag.pointee.count } - subscript(index: Int) -> NdbTagElem? { - guard index < count else { return nil } + func strings() -> [String] { + return self.map { $0.string() } + } + + subscript(index: Int) -> NdbTagElem { + precondition(index < count, "Index out of bounds") return NdbTagElem(note: note, tag: tag, index: Int32(index)) } diff --git a/nostrdb/Test/NdbTests.swift b/nostrdb/Test/NdbTests.swift @@ -52,7 +52,7 @@ final class NdbTests: XCTestCase { } if tags == 7 { - XCTAssertEqual(tag[2]?.string(), "wss://nostr-pub.wellorder.net") + XCTAssertEqual(tag[2].string(), "wss://nostr-pub.wellorder.net") } for elem in tag {