This change addresses an issue where notes with quotes sometimes are not loaded correctly because the quoted note was not available in the same relay. Now whenever a user posts a note with a quoted note, the quoted note is also broadcast to the user's selected relays. Issue repro ----------- ISSUE REPRODUCED Device: iPhone 14 Pro Simulator iOS: 17.0 Damus: `1fabd4c0fe98d1f47b1fa0f76984ad78095bd49c` Setup: - Make sure you have a debugger connected - Have a test note that you can quote Steps: 1. Start Damus and let logs settle 2. Observe where the last log is 3. Quote the test note 4. Copy newly generated logs and paste on a text editor. 5. Analyze those logs. Pay attention to the new note id, as well as the note id of the quoted event (`["q", <QUOTED_NOTE_ID>]`) Results: Logs show that the newly posted event is being flushed to the relays, but not the note that is being quoted. Testing of the fix ------------------ PASS Device: iPhone 14 Pro Simulator iOS: 17.0 Damus: This commit Setup: - Make sure you have a debugger connected - Have a test note that you can quote Steps: 1. Start Damus and let logs settle 2. Observe where the last log is 3. Quote the test note 4. Copy newly generated logs and paste on a text editor. 5. Analyze those logs. Pay attention to the new note id, as well as the note id of the quoted event (`["q", <QUOTED_NOTE_ID>]`) Results: - Logs show the new event being flushed to the relays. PASS - Logs show the quoted event also being flushed to the relays. PASS Closes: https://github.com/damus-io/damus/issues/1495 Changelog-Fixed: Broadcast quoted notes when posting a note with quotes Signed-off-by: Daniel D’Aquino <daniel@daquino.me> Reviewed-by: William Casarin <jb55@jb55.com> Signed-off-by: William Casarin <jb55@jb55.com>
140 lines
2.7 KiB
Swift
140 lines
2.7 KiB
Swift
//
|
|
// Id.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2023-07-26.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
struct TagRef<T>: Hashable, Equatable, Encodable {
|
|
let elem: TagElem
|
|
|
|
init(_ elem: TagElem) {
|
|
self.elem = elem
|
|
}
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
var container = encoder.singleValueContainer()
|
|
try container.encode(elem.string())
|
|
}
|
|
}
|
|
|
|
protocol TagKey {
|
|
var keychar: AsciiCharacter { get }
|
|
}
|
|
|
|
protocol TagKeys {
|
|
associatedtype TagKeys: TagKey
|
|
var key: TagKeys { get }
|
|
}
|
|
|
|
protocol TagConvertible {
|
|
var tag: [String] { get }
|
|
static func from_tag(tag: TagSequence) -> Self?
|
|
}
|
|
|
|
struct QuoteId: IdType, TagKey, TagConvertible {
|
|
let id: Data
|
|
|
|
init(_ data: Data) {
|
|
self.id = data
|
|
}
|
|
|
|
/// Refer to this QuoteId as a NoteId
|
|
var note_id: NoteId {
|
|
NoteId(self.id)
|
|
}
|
|
|
|
var keychar: AsciiCharacter { "q" }
|
|
|
|
var tag: [String] {
|
|
["q", self.hex()]
|
|
}
|
|
|
|
static func from_tag(tag: TagSequence) -> QuoteId? {
|
|
var i = tag.makeIterator()
|
|
|
|
guard tag.count >= 2,
|
|
let t0 = i.next(),
|
|
let key = t0.single_char,
|
|
key == "q",
|
|
let t1 = i.next(),
|
|
let quote_id = t1.id().map(QuoteId.init)
|
|
else { return nil }
|
|
|
|
return quote_id
|
|
}
|
|
}
|
|
|
|
|
|
struct Privkey: IdType {
|
|
let id: Data
|
|
|
|
var nsec: String {
|
|
bech32_privkey(self)
|
|
}
|
|
|
|
init?(hex: String) {
|
|
guard let id = hex_decode_id(hex) else {
|
|
return nil
|
|
}
|
|
self.init(id)
|
|
}
|
|
|
|
init(_ data: Data) {
|
|
self.id = data
|
|
}
|
|
}
|
|
|
|
|
|
struct Hashtag: TagConvertible, Hashable {
|
|
let hashtag: String
|
|
|
|
static func from_tag(tag: TagSequence) -> Hashtag? {
|
|
var i = tag.makeIterator()
|
|
|
|
guard tag.count >= 2,
|
|
let t0 = i.next(),
|
|
let chr = t0.single_char,
|
|
chr == "t",
|
|
let t1 = i.next() else {
|
|
return nil
|
|
}
|
|
|
|
return Hashtag(hashtag: t1.string())
|
|
}
|
|
|
|
var tag: [String] { ["t", self.hashtag] }
|
|
var keychar: AsciiCharacter { "t" }
|
|
}
|
|
|
|
struct ReplaceableParam: TagConvertible {
|
|
let param: TagElem
|
|
|
|
static func from_tag(tag: TagSequence) -> ReplaceableParam? {
|
|
var i = tag.makeIterator()
|
|
|
|
guard tag.count >= 2,
|
|
let t0 = i.next(),
|
|
let chr = t0.single_char,
|
|
chr == "d",
|
|
let t1 = i.next() else {
|
|
return nil
|
|
}
|
|
|
|
return ReplaceableParam(param: t1)
|
|
}
|
|
|
|
var tag: [String] { [self.keychar.description, self.param.string()] }
|
|
var keychar: AsciiCharacter { "d" }
|
|
}
|
|
|
|
struct Signature: Hashable, Equatable {
|
|
let data: Data
|
|
|
|
init(_ p: Data) {
|
|
self.data = p
|
|
}
|
|
}
|