Extract and use relay hints from bech32 entities (nevent, nprofile, naddr) and event tag references (e, q tags) to fetch events from hinted relays not in the user's relay pool. Changes: - Parse relay hints from bech32 TLV data in URLHandler - Pass relay hints through SearchType and NoteReference enums - Add ensureConnected() to RelayPool for ephemeral relay connections - Implement ephemeral relay lease management with race condition protection - Add repostTarget() helper to extract relay hints from repost e tags - Add QuoteRef struct to preserve relay hints from q tags (NIP-10/NIP-18) - Support relay hints in replies with author pubkey in e-tags (NIP-10) - Implement fallback broadcast when hinted relays don't respond - Add comprehensive test coverage for relay hint functionality - Add DEBUG logging for relay hint tracing during development Implementation details: - Connect to hinted relays as ephemeral, returning early when first connects - Use total deadline to prevent timeout accumulation across hint attempts - Decrement lease count before suspension points to ensure atomicity - Fall back to broadcast if hints don't resolve or respond Closes: https://github.com/damus-io/damus/issues/1147 Changelog-Added: Added relay hint support for nevent, nprofile, naddr links and event tag references (reposts, quotes, replies) Signed-off-by: alltheseas Signed-off-by: Daniel D'Aquino <daniel@daquino.me> Co-authored-by: alltheseas <alltheseas@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Daniel D'Aquino <daniel@daquino.me
58 lines
1.7 KiB
Swift
58 lines
1.7 KiB
Swift
//
|
||
// NdbNote+.swift
|
||
// damus
|
||
//
|
||
// Created by Daniel D’Aquino on 2023-11-17.
|
||
//
|
||
|
||
import Foundation
|
||
|
||
// Extension to make NdbNote compatible with NostrEvent's original API
|
||
extension NdbNote {
|
||
func parse_inner_event() -> NdbNote? {
|
||
return NdbNote.owned_from_json_cstr(json: content_raw, json_len: content_len)
|
||
}
|
||
|
||
func get_cached_inner_event(cache: EventCache) -> NdbNote? {
|
||
guard self.known_kind == .boost || self.known_kind == .highlight else {
|
||
return nil
|
||
}
|
||
|
||
if self.content_len == 0, let id = self.referenced_ids.first {
|
||
// TODO: raw id cache lookups
|
||
return cache.lookup(id)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func get_inner_event(cache: EventCache) -> NdbNote? {
|
||
if let ev = get_cached_inner_event(cache: cache) {
|
||
return ev
|
||
}
|
||
return self.parse_inner_event()
|
||
}
|
||
|
||
/// Returns the target event ID and relay hints for a repost (kind 6) event.
|
||
///
|
||
/// Per NIP-18, reposts MUST include an `e` tag with the reposted event's ID,
|
||
/// and the tag MUST include a relay URL as its third entry.
|
||
///
|
||
/// - Returns: A tuple of (noteId, relayHints) if this is a repost with a valid e tag, nil otherwise.
|
||
func repostTarget() -> (noteId: NoteId, relayHints: [RelayURL])? {
|
||
guard self.known_kind == .boost else { return nil }
|
||
|
||
for tag in self.tags {
|
||
guard tag.count >= 2 else { continue }
|
||
guard tag[0].matches_char("e") else { continue }
|
||
guard let noteIdData = tag[1].id() else { continue }
|
||
|
||
let noteId = NoteId(noteIdData)
|
||
let relayHints = tag.relayHints
|
||
return (noteId, relayHints)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
}
|