Files
damus/damus/Nostr/Id.swift
Daniel D’Aquino a06be64894 network: Broadcast quoted notes when posting a note with quotes
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>
2023-10-07 14:49:53 -07:00

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
}
}