Files
damus/damus/Features/DMs/Views/DMView.swift
alltheseas 9a1ae6f9b5 Consume NIP-19 relay hints for event fetching
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
2026-02-02 18:52:41 -08:00

84 lines
2.5 KiB
Swift

//
// DMView.swift
// damus
//
// Created by William Casarin on 2022-07-01.
//
import SwiftUI
struct DMView: View {
let event: NostrEvent
let damus_state: DamusState
var is_ours: Bool {
event.pubkey == damus_state.pubkey
}
var Mention: some View {
Group {
if let mention = first_eref_mention_with_hints(ndb: damus_state.ndb, ev: event, keypair: damus_state.keypair) {
BuilderEventView(damus: damus_state, event_id: mention.noteId, relayHints: mention.relayHints)
} else {
EmptyView()
}
}
}
var dm_options: EventViewOptions {
/*
if self.damus_state.settings.translate_dms {
return []
}
*/
return [.no_translate]
}
var DM: some View {
HStack {
if is_ours {
Spacer(minLength: UIScreen.main.bounds.width * 0.2)
}
let should_blur_img = should_blur_images(settings: damus_state.settings, contacts: damus_state.contacts, ev: event, our_pubkey: damus_state.pubkey)
VStack(alignment: .trailing) {
NoteContentView(damus_state: damus_state, event: event, blur_images: should_blur_img, size: .normal, options: dm_options)
.fixedSize(horizontal: false, vertical: true)
.padding([.top, .leading, .trailing], 10)
.padding([.bottom], 10)
.background(VisualEffectView(effect: UIBlurEffect(style: .prominent))
.background(is_ours ? Color.accentColor.opacity(0.9) : Color.secondary.opacity(0.15))
)
.cornerRadius(8.0)
.tint(is_ours ? Color.white : Color.accentColor)
Text(format_relative_time(event.created_at))
.font(.footnote)
.foregroundColor(.gray)
.opacity(0.8)
}
if !is_ours {
Spacer(minLength: UIScreen.main.bounds.width * 0.2)
}
}
}
var body: some View {
VStack {
Mention
DM
}
}
}
struct DMView_Previews: PreviewProvider {
static var previews: some View {
let ev = NostrEvent(content: "Hey there *buddy*, want to grab some drinks later? 🍻", keypair: test_keypair, kind: 1, tags: [])!
DMView(event: ev, damus_state: test_damus_state)
}
}