NIP-65 relay list models and definitions
This commit adds the base models needed for the NIP-65 relay list support. This introduces no user-facing changes. Changelog-None Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -1649,6 +1649,9 @@
|
|||||||
D7DB93052D66A44100DA1EE5 /* Undistractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */; };
|
D7DB93052D66A44100DA1EE5 /* Undistractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */; };
|
||||||
D7DB93062D66A44100DA1EE5 /* Undistractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */; };
|
D7DB93062D66A44100DA1EE5 /* Undistractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */; };
|
||||||
D7DB93072D66A44100DA1EE5 /* Undistractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */; };
|
D7DB93072D66A44100DA1EE5 /* Undistractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */; };
|
||||||
|
D7DB930A2D69486700DA1EE5 /* NIP65.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93092D69485A00DA1EE5 /* NIP65.swift */; };
|
||||||
|
D7DB930B2D69486700DA1EE5 /* NIP65.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93092D69485A00DA1EE5 /* NIP65.swift */; };
|
||||||
|
D7DB930C2D69486700DA1EE5 /* NIP65.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DB93092D69485A00DA1EE5 /* NIP65.swift */; };
|
||||||
D7DBD41F2B02F15E002A6197 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; };
|
D7DBD41F2B02F15E002A6197 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; };
|
||||||
D7DEEF2F2A8C021E00E0C99F /* NostrEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */; };
|
D7DEEF2F2A8C021E00E0C99F /* NostrEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */; };
|
||||||
D7EB00B02CD59C8D00660C07 /* PresentFullScreenItemNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EB00AF2CD59C8300660C07 /* PresentFullScreenItemNotify.swift */; };
|
D7EB00B02CD59C8D00660C07 /* PresentFullScreenItemNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EB00AF2CD59C8300660C07 /* PresentFullScreenItemNotify.swift */; };
|
||||||
@@ -2537,6 +2540,7 @@
|
|||||||
D7DB1FF02D5AC5D700CF06DA /* nip44.vectors.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = nip44.vectors.json; sourceTree = "<group>"; };
|
D7DB1FF02D5AC5D700CF06DA /* nip44.vectors.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = nip44.vectors.json; sourceTree = "<group>"; };
|
||||||
D7DB1FF22D5AC5E400CF06DA /* LICENSES */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSES; sourceTree = "<group>"; };
|
D7DB1FF22D5AC5E400CF06DA /* LICENSES */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSES; sourceTree = "<group>"; };
|
||||||
D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Undistractor.swift; sourceTree = "<group>"; };
|
D7DB93042D66A43B00DA1EE5 /* Undistractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Undistractor.swift; sourceTree = "<group>"; };
|
||||||
|
D7DB93092D69485A00DA1EE5 /* NIP65.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP65.swift; sourceTree = "<group>"; };
|
||||||
D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrEventTests.swift; sourceTree = "<group>"; };
|
D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrEventTests.swift; sourceTree = "<group>"; };
|
||||||
D7EB00AF2CD59C8300660C07 /* PresentFullScreenItemNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentFullScreenItemNotify.swift; sourceTree = "<group>"; };
|
D7EB00AF2CD59C8300660C07 /* PresentFullScreenItemNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentFullScreenItemNotify.swift; sourceTree = "<group>"; };
|
||||||
D7EDED1B2B1178FE0018B19C /* NoteContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteContent.swift; sourceTree = "<group>"; };
|
D7EDED1B2B1178FE0018B19C /* NoteContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteContent.swift; sourceTree = "<group>"; };
|
||||||
@@ -3646,6 +3650,7 @@
|
|||||||
4CE6DEE527F7A08100C66700 /* damus */ = {
|
4CE6DEE527F7A08100C66700 /* damus */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D7DB93082D69478400DA1EE5 /* NIP65 */,
|
||||||
D7DB1FDC2D5A77E500CF06DA /* NIP44 */,
|
D7DB1FDC2D5A77E500CF06DA /* NIP44 */,
|
||||||
D755B28B2D3E7D6500BBEEFA /* NIP37 */,
|
D755B28B2D3E7D6500BBEEFA /* NIP37 */,
|
||||||
D78F08152D7F7F5F00FC6C75 /* NIP04 */,
|
D78F08152D7F7F5F00FC6C75 /* NIP04 */,
|
||||||
@@ -4044,6 +4049,14 @@
|
|||||||
path = NIP44;
|
path = NIP44;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D7DB93082D69478400DA1EE5 /* NIP65 */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D7DB93092D69485A00DA1EE5 /* NIP65.swift */,
|
||||||
|
);
|
||||||
|
path = NIP65;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E06336A72B7582D600A88E6B /* Assets */ = {
|
E06336A72B7582D600A88E6B /* Assets */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -4480,6 +4493,7 @@
|
|||||||
F757933A29D7AECD007DEAC1 /* MediaPicker.swift in Sources */,
|
F757933A29D7AECD007DEAC1 /* MediaPicker.swift in Sources */,
|
||||||
4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */,
|
4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */,
|
||||||
B57B4C662B312C3700A232C0 /* NostrAuth.swift in Sources */,
|
B57B4C662B312C3700A232C0 /* NostrAuth.swift in Sources */,
|
||||||
|
D7DB930B2D69486700DA1EE5 /* NIP65.swift in Sources */,
|
||||||
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */,
|
4CB8838D296F710400DC99E7 /* Reposted.swift in Sources */,
|
||||||
4C3EA67728FF7A9800C48A62 /* talstr.c in Sources */,
|
4C3EA67728FF7A9800C48A62 /* talstr.c in Sources */,
|
||||||
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
||||||
@@ -5311,6 +5325,7 @@
|
|||||||
82D6FBE02CD99F7900C925F4 /* ReactionsSettingsView.swift in Sources */,
|
82D6FBE02CD99F7900C925F4 /* ReactionsSettingsView.swift in Sources */,
|
||||||
82D6FBE12CD99F7900C925F4 /* NotificationSettingsView.swift in Sources */,
|
82D6FBE12CD99F7900C925F4 /* NotificationSettingsView.swift in Sources */,
|
||||||
82D6FBE22CD99F7900C925F4 /* AppearanceSettingsView.swift in Sources */,
|
82D6FBE22CD99F7900C925F4 /* AppearanceSettingsView.swift in Sources */,
|
||||||
|
D7DB930A2D69486700DA1EE5 /* NIP65.swift in Sources */,
|
||||||
82D6FBE32CD99F7900C925F4 /* KeySettingsView.swift in Sources */,
|
82D6FBE32CD99F7900C925F4 /* KeySettingsView.swift in Sources */,
|
||||||
82D6FBE42CD99F7900C925F4 /* ZapSettingsView.swift in Sources */,
|
82D6FBE42CD99F7900C925F4 /* ZapSettingsView.swift in Sources */,
|
||||||
82D6FBE52CD99F7900C925F4 /* TranslationSettingsView.swift in Sources */,
|
82D6FBE52CD99F7900C925F4 /* TranslationSettingsView.swift in Sources */,
|
||||||
@@ -5715,6 +5730,7 @@
|
|||||||
D73E5F012C6A97F4007EB227 /* ZapTypePicker.swift in Sources */,
|
D73E5F012C6A97F4007EB227 /* ZapTypePicker.swift in Sources */,
|
||||||
D73E5F022C6A97F4007EB227 /* ZapUserView.swift in Sources */,
|
D73E5F022C6A97F4007EB227 /* ZapUserView.swift in Sources */,
|
||||||
D73E5F032C6A97F4007EB227 /* ProfileZapLinkView.swift in Sources */,
|
D73E5F032C6A97F4007EB227 /* ProfileZapLinkView.swift in Sources */,
|
||||||
|
D7DB930C2D69486700DA1EE5 /* NIP65.swift in Sources */,
|
||||||
D73E5F042C6A97F4007EB227 /* AboutView.swift in Sources */,
|
D73E5F042C6A97F4007EB227 /* AboutView.swift in Sources */,
|
||||||
D73E5F052C6A97F4007EB227 /* ProfileName.swift in Sources */,
|
D73E5F052C6A97F4007EB227 /* ProfileName.swift in Sources */,
|
||||||
D73E5F062C6A97F4007EB227 /* ProfilePictureSelector.swift in Sources */,
|
D73E5F062C6A97F4007EB227 /* ProfilePictureSelector.swift in Sources */,
|
||||||
|
|||||||
@@ -225,6 +225,8 @@ class HomeModel: ContactsDelegate {
|
|||||||
// TODO: Implement draft syncing with relays. We intentionally do not support that as of writing. See `DraftsModel.swift` for other details
|
// TODO: Implement draft syncing with relays. We intentionally do not support that as of writing. See `DraftsModel.swift` for other details
|
||||||
// try? damus_state.drafts.load(wrapped_draft_note: ev, with: damus_state)
|
// try? damus_state.drafts.load(wrapped_draft_note: ev, with: damus_state)
|
||||||
break
|
break
|
||||||
|
case .relay_list:
|
||||||
|
break // This will be handled by `UserRelayListManager`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -336,6 +336,10 @@ class UserSettingsStore: ObservableObject {
|
|||||||
@Setting(key: "draft_event_ids", default_value: nil)
|
@Setting(key: "draft_event_ids", default_value: nil)
|
||||||
var draft_event_ids: [String]?
|
var draft_event_ids: [String]?
|
||||||
|
|
||||||
|
// TODO: Get rid of this once we have NostrDB query capabilities integrated
|
||||||
|
@Setting(key: "latest_relay_list_event_id", default_value: nil)
|
||||||
|
var latestRelayListEventIdHex: String?
|
||||||
|
|
||||||
// MARK: Helper types
|
// MARK: Helper types
|
||||||
|
|
||||||
enum NotificationsMode: String, CaseIterable, Identifiable, StringCodable, Equatable {
|
enum NotificationsMode: String, CaseIterable, Identifiable, StringCodable, Equatable {
|
||||||
|
|||||||
167
damus/NIP65/NIP65.swift
Normal file
167
damus/NIP65/NIP65.swift
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
//
|
||||||
|
// NIP65.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by Daniel D’Aquino on 2025-02-21.
|
||||||
|
//
|
||||||
|
// Some text excerpts taken from the Nostr Protocol itself (which are public domain)
|
||||||
|
|
||||||
|
import OrderedCollections
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Includes models and functions for working with NIP-65
|
||||||
|
struct NIP65: Sendable {}
|
||||||
|
|
||||||
|
extension NIP65 {
|
||||||
|
/// Models a NIP-65 relay list
|
||||||
|
struct RelayList: NostrEventConvertible, Sendable {
|
||||||
|
let relays: OrderedDictionary<RelayURL, RelayItem>
|
||||||
|
|
||||||
|
// MARK: - Initialization
|
||||||
|
|
||||||
|
init(event: NdbNote) throws(NIP65DecodingError) {
|
||||||
|
guard event.known_kind == .relay_list else { throw .notRelayList }
|
||||||
|
var relays: [RelayItem] = []
|
||||||
|
for tag in event.tags {
|
||||||
|
guard let relay = try RelayItem.fromTag(tag: tag) else { continue }
|
||||||
|
relays.append(relay)
|
||||||
|
}
|
||||||
|
self.relays = Self.relayOrderedDictionary(from: relays)
|
||||||
|
}
|
||||||
|
|
||||||
|
init?(event: NdbNote?) throws(NIP65DecodingError) {
|
||||||
|
guard let event else { return nil }
|
||||||
|
try self.init(event: event)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(relays: [RelayItem]) {
|
||||||
|
self.relays = Self.relayOrderedDictionary(from: relays)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(relays: [RelayURL]) {
|
||||||
|
let relayItemList = relays.map({ RelayItem(url: $0, rwConfiguration: .readWrite) })
|
||||||
|
self.relays = Self.relayOrderedDictionary(from: relayItemList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func relayOrderedDictionary(from relayList: [RelayItem]) -> OrderedDictionary<RelayURL, RelayItem> {
|
||||||
|
var seenUrls: Set<RelayURL> = []
|
||||||
|
return OrderedDictionary(uniqueKeysWithValues: relayList.compactMap({
|
||||||
|
// We need to ensure the keys are unique to avoid assertion errors from OrderedDictionary
|
||||||
|
guard !seenUrls.contains($0.url) else { return nil }
|
||||||
|
seenUrls.insert($0.url)
|
||||||
|
return ($0.url, $0)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Conversion to a Nostr Event
|
||||||
|
|
||||||
|
func toNostrEvent(keypair: FullKeypair, timestamp: UInt32? = nil) -> NostrEvent? {
|
||||||
|
return NdbNote(
|
||||||
|
content: "",
|
||||||
|
keypair: keypair.to_keypair(),
|
||||||
|
kind: NostrKind.relay_list.rawValue,
|
||||||
|
tags: self.relays.values.map({ $0.tag }),
|
||||||
|
createdAt: timestamp ?? UInt32(Date.now.timeIntervalSince1970)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NIP65 {
|
||||||
|
/// An error thrown when decoding an item into a NIP-65 relay list
|
||||||
|
enum NIP65DecodingError: Error {
|
||||||
|
/// The Nostr event being converted is not a NIP-65 relay list
|
||||||
|
case notRelayList
|
||||||
|
/// The relay URL is invalid
|
||||||
|
case invalidRelayURL
|
||||||
|
///The relay RW marker is invalid
|
||||||
|
case invalidRelayMarker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NIP65.RelayList {
|
||||||
|
/// An item referencing a relay and its configuration inside a relay list
|
||||||
|
struct RelayItem: ThrowingTagConvertible, Sendable {
|
||||||
|
typealias E = NIP65.NIP65DecodingError
|
||||||
|
|
||||||
|
let url: RelayURL
|
||||||
|
let rwConfiguration: RWConfiguration
|
||||||
|
|
||||||
|
/// The raw tag sequence in a Nostr event
|
||||||
|
var tag: [String] {
|
||||||
|
var tag = ["r", url.absoluteString]
|
||||||
|
if let rwMarker = rwConfiguration.tagItem { tag.append(rwMarker) }
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a new relay item from a Nostr event's tag sequence
|
||||||
|
static func fromTag(tag: TagSequence) throws(E) -> NIP65.RelayList.RelayItem? {
|
||||||
|
var i = tag.makeIterator()
|
||||||
|
|
||||||
|
guard tag.count >= 2,
|
||||||
|
let t0 = i.next(),
|
||||||
|
let key = t0.single_char,
|
||||||
|
let rkey = RefId.RefKey(rawValue: key),
|
||||||
|
let t1 = i.next()
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
|
let t2 = i.next()
|
||||||
|
|
||||||
|
switch rkey {
|
||||||
|
case .r: return try self.fromRawInfo(urlString: t1.string(), rwMarker: t2?.string())
|
||||||
|
// Keep options explicit to make compiler prompt developer on whether to ignore or handle new future options
|
||||||
|
case .e, .p, .q, .t, .d, .a: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes a Relay Item based on raw information
|
||||||
|
static func fromRawInfo(urlString: String, rwMarker: String?) throws(NIP65.NIP65DecodingError) -> NIP65.RelayList.RelayItem? {
|
||||||
|
guard let relayUrl = RelayURL(urlString) else { throw .invalidRelayURL }
|
||||||
|
guard let rwConfiguration = RWConfiguration.fromTagItem(rwMarker) else { throw .invalidRelayMarker }
|
||||||
|
return NIP65.RelayList.RelayItem(url: relayUrl, rwConfiguration: rwConfiguration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NIP65.RelayList.RelayItem {
|
||||||
|
/// The read/write configuration for a relay item
|
||||||
|
enum RWConfiguration: TagItemConvertible {
|
||||||
|
case read
|
||||||
|
case write
|
||||||
|
case readWrite
|
||||||
|
|
||||||
|
static let READ_MARKER: String = "read"
|
||||||
|
static let WRITE_MARKER: String = "write"
|
||||||
|
|
||||||
|
var canRead: Bool {
|
||||||
|
switch self {
|
||||||
|
case .read, .readWrite: return true
|
||||||
|
case .write: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var canWrite: Bool {
|
||||||
|
switch self {
|
||||||
|
case .write, .readWrite: return true
|
||||||
|
case .read: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A raw Nostr Event tag item
|
||||||
|
var tagItem: String? {
|
||||||
|
switch self {
|
||||||
|
case .read: Self.READ_MARKER
|
||||||
|
case .write: Self.WRITE_MARKER
|
||||||
|
case .readWrite: nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize this from a raw Nostr Event tag item
|
||||||
|
static func fromTagItem(_ item: String?) -> Self? {
|
||||||
|
if item == READ_MARKER { return .read }
|
||||||
|
if item == WRITE_MARKER { return .write }
|
||||||
|
return .readWrite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,19 @@ protocol TagConvertible {
|
|||||||
static func from_tag(tag: TagSequence) -> Self?
|
static func from_tag(tag: TagSequence) -> Self?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Protocol for types that can be converted from/to a tag sequence with the possibilty of an error
|
||||||
|
protocol ThrowingTagConvertible {
|
||||||
|
associatedtype E: Error
|
||||||
|
var tag: [String] { get }
|
||||||
|
static func fromTag(tag: TagSequence) throws(E) -> Self?
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Protocol for types that can be converted from/to a tag item
|
||||||
|
protocol TagItemConvertible {
|
||||||
|
var tagItem: String? { get }
|
||||||
|
static func fromTagItem(_ item: String?) -> Self?
|
||||||
|
}
|
||||||
|
|
||||||
struct QuoteId: IdType, TagKey, TagConvertible {
|
struct QuoteId: IdType, TagKey, TagConvertible {
|
||||||
let id: Data
|
let id: Data
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ enum NostrKind: UInt32, Codable {
|
|||||||
case like = 7
|
case like = 7
|
||||||
case chat = 42
|
case chat = 42
|
||||||
case mute_list = 10000
|
case mute_list = 10000
|
||||||
|
case relay_list = 10002
|
||||||
case list_deprecated = 30000
|
case list_deprecated = 30000
|
||||||
case draft = 31234
|
case draft = 31234
|
||||||
case longform = 30023
|
case longform = 30023
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ public struct LegacyKind3RelayRWConfiguration: Codable, Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static let rw = LegacyKind3RelayRWConfiguration(read: true, write: true)
|
static let rw = LegacyKind3RelayRWConfiguration(read: true, write: true)
|
||||||
|
|
||||||
|
func toNIP65RWConfiguration() -> NIP65.RelayList.RelayItem.RWConfiguration? {
|
||||||
|
switch (self.read, self.write) {
|
||||||
|
case (false, true): return .write
|
||||||
|
case (true, false): return .read
|
||||||
|
case (true, true): return .readWrite
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RelayVariant {
|
enum RelayVariant {
|
||||||
@@ -162,3 +171,26 @@ extension RelayPool {
|
|||||||
case RelayAlreadyExists
|
case RelayAlreadyExists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Extension to bridge NIP-65 relay list structs with app-native objects
|
||||||
|
|
||||||
|
extension NIP65.RelayList {
|
||||||
|
static func fromLegacyContactList(_ contactList: NdbNote) throws(BridgeError) -> Self {
|
||||||
|
guard let relayListInfo = decode_json_relays(contactList.content) else { throw .couldNotDecodeRelayListInfo }
|
||||||
|
let relayItems = relayListInfo.map({ url, rwConfiguration in
|
||||||
|
return RelayItem(url: url, rwConfiguration: rwConfiguration.toNIP65RWConfiguration() ?? .readWrite)
|
||||||
|
})
|
||||||
|
return NIP65.RelayList(relays: relayItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func fromLegacyContactList(_ contactList: NdbNote?) throws(BridgeError) -> Self? {
|
||||||
|
guard let contactList = contactList else { return nil }
|
||||||
|
return try fromLegacyContactList(contactList)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BridgeError: Error {
|
||||||
|
case couldNotDecodeRelayListInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class LoadableNostrEventViewModel: ObservableObject {
|
|||||||
case .zap, .zap_request:
|
case .zap, .zap_request:
|
||||||
guard let zap = await get_zap(from: ev, state: damus_state) else { return .not_found }
|
guard let zap = await get_zap(from: ev, state: damus_state) else { return .not_found }
|
||||||
return .loaded(route: Route.Zaps(target: zap.target))
|
return .loaded(route: Route.Zaps(target: zap.target))
|
||||||
case .contacts, .metadata, .delete, .boost, .chat, .mute_list, .list_deprecated, .draft, .longform, .nwc_request, .nwc_response, .http_auth, .status:
|
case .contacts, .metadata, .delete, .boost, .chat, .mute_list, .list_deprecated, .draft, .longform, .nwc_request, .nwc_response, .http_auth, .status, .relay_list:
|
||||||
return .unknown_or_unsupported_kind
|
return .unknown_or_unsupported_kind
|
||||||
}
|
}
|
||||||
case .naddr(let naddr):
|
case .naddr(let naddr):
|
||||||
|
|||||||
Reference in New Issue
Block a user