mirror of
git://jb55.com/damus
synced 2024-09-30 00:40:45 +00:00
relay pool!
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
a32243ab15
commit
13b01381d7
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
4C75EFA427FA577B0006080F /* PostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75EFA327FA577B0006080F /* PostView.swift */; };
|
4C75EFA427FA577B0006080F /* PostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75EFA327FA577B0006080F /* PostView.swift */; };
|
||||||
|
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75EFA527FF87A20006080F /* Nostr.swift */; };
|
||||||
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DEE627F7A08100C66700 /* damusApp.swift */; };
|
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DEE627F7A08100C66700 /* damusApp.swift */; };
|
||||||
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DEE827F7A08100C66700 /* ContentView.swift */; };
|
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DEE827F7A08100C66700 /* ContentView.swift */; };
|
||||||
4CE6DEEB27F7A08200C66700 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4CE6DEEA27F7A08200C66700 /* Assets.xcassets */; };
|
4CE6DEEB27F7A08200C66700 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4CE6DEEA27F7A08200C66700 /* Assets.xcassets */; };
|
||||||
@ -16,8 +17,7 @@
|
|||||||
4CE6DF0227F7A08200C66700 /* damusUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0127F7A08200C66700 /* damusUITests.swift */; };
|
4CE6DF0227F7A08200C66700 /* damusUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0127F7A08200C66700 /* damusUITests.swift */; };
|
||||||
4CE6DF0427F7A08200C66700 /* damusUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */; };
|
4CE6DF0427F7A08200C66700 /* damusUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */; };
|
||||||
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 4CE6DF1127F7A2B300C66700 /* Starscream */; };
|
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 4CE6DF1127F7A2B300C66700 /* Starscream */; };
|
||||||
4CE6DF1427F7A45200C66700 /* WSConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1327F7A45200C66700 /* WSConnection.swift */; };
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */; };
|
||||||
4CE6DF1627F8DEBF00C66700 /* NostrConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* NostrConnection.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
4C75EFA327FA577B0006080F /* PostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostView.swift; sourceTree = "<group>"; };
|
4C75EFA327FA577B0006080F /* PostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostView.swift; sourceTree = "<group>"; };
|
||||||
|
4C75EFA527FF87A20006080F /* Nostr.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nostr.swift; sourceTree = "<group>"; };
|
||||||
4CE6DEE327F7A08100C66700 /* damus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = damus.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
4CE6DEE327F7A08100C66700 /* damus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = damus.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
4CE6DEE627F7A08100C66700 /* damusApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusApp.swift; sourceTree = "<group>"; };
|
4CE6DEE627F7A08100C66700 /* damusApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusApp.swift; sourceTree = "<group>"; };
|
||||||
4CE6DEE827F7A08100C66700 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
4CE6DEE827F7A08100C66700 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
@ -49,8 +50,7 @@
|
|||||||
4CE6DEFD27F7A08200C66700 /* damusUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = damusUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
4CE6DEFD27F7A08200C66700 /* damusUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = damusUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
4CE6DF0127F7A08200C66700 /* damusUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITests.swift; sourceTree = "<group>"; };
|
4CE6DF0127F7A08200C66700 /* damusUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITests.swift; sourceTree = "<group>"; };
|
||||||
4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||||
4CE6DF1327F7A45200C66700 /* WSConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WSConnection.swift; sourceTree = "<group>"; };
|
4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConnection.swift; sourceTree = "<group>"; };
|
||||||
4CE6DF1527F8DEBF00C66700 /* NostrConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrConnection.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -115,8 +115,8 @@
|
|||||||
4CE6DEE827F7A08100C66700 /* ContentView.swift */,
|
4CE6DEE827F7A08100C66700 /* ContentView.swift */,
|
||||||
4CE6DEEA27F7A08200C66700 /* Assets.xcassets */,
|
4CE6DEEA27F7A08200C66700 /* Assets.xcassets */,
|
||||||
4CE6DEEC27F7A08200C66700 /* Preview Content */,
|
4CE6DEEC27F7A08200C66700 /* Preview Content */,
|
||||||
4CE6DF1327F7A45200C66700 /* WSConnection.swift */,
|
4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */,
|
||||||
4CE6DF1527F8DEBF00C66700 /* NostrConnection.swift */,
|
4C75EFA527FF87A20006080F /* Nostr.swift */,
|
||||||
);
|
);
|
||||||
path = damus;
|
path = damus;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -283,8 +283,8 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
4CE6DEE927F7A08100C66700 /* ContentView.swift in Sources */,
|
||||||
4CE6DF1427F7A45200C66700 /* WSConnection.swift in Sources */,
|
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
|
||||||
4CE6DF1627F8DEBF00C66700 /* NostrConnection.swift in Sources */,
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
||||||
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */,
|
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */,
|
||||||
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
|
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -10,10 +10,11 @@ import Starscream
|
|||||||
|
|
||||||
struct EventView: View {
|
struct EventView: View {
|
||||||
let event: NostrEvent
|
let event: NostrEvent
|
||||||
|
let profile: Profile?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text(String(event.pubkey.prefix(16)))
|
Text(String(profile?.name ?? String(event.pubkey.prefix(16))))
|
||||||
.bold()
|
.bold()
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
UIPasteboard.general.string = event.pubkey
|
UIPasteboard.general.string = event.pubkey
|
||||||
@ -43,14 +44,15 @@ struct ContentView: View {
|
|||||||
@State var sub_id: String? = nil
|
@State var sub_id: String? = nil
|
||||||
@State var active_sheet: Sheets? = nil
|
@State var active_sheet: Sheets? = nil
|
||||||
@State var events: [NostrEvent] = []
|
@State var events: [NostrEvent] = []
|
||||||
|
@State var profiles: [String: Profile] = [:]
|
||||||
@State var has_events: [String: Bool] = [:]
|
@State var has_events: [String: Bool] = [:]
|
||||||
@State var loading: Bool = true
|
@State var loading: Bool = true
|
||||||
@State var connection: NostrConnection? = nil
|
@State var pool: RelayPool? = nil
|
||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
ForEach(events.reversed(), id: \.id) {
|
ForEach(events.reversed(), id: \.id) {
|
||||||
EventView(event: $0)
|
EventView(event: $0, profile: profiles[$0.pubkey])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,28 +88,46 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
func connect() {
|
||||||
let url = URL(string: "wss://nostr.bitcoiner.social")!
|
let pool = RelayPool(handle_event: handle_event)
|
||||||
let conn = NostrConnection(url: url, handleEvent: handle_event)
|
|
||||||
conn.connect()
|
add_rw_relay(pool, "wss://nostr-pub.wellorder.net")
|
||||||
self.connection = conn
|
add_rw_relay(pool, "wss://nostr-relay.wlvs.space")
|
||||||
|
add_rw_relay(pool, "wss://nostr.bitcoiner.social")
|
||||||
|
|
||||||
|
self.pool = pool
|
||||||
|
pool.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_event(conn_event: NostrConnectionEvent) {
|
func handle_contact_event(_ ev: NostrEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_metadata_event(_ ev: NostrEvent) {
|
||||||
|
guard let profile: Profile = decode_data(Data(ev.content.utf8)) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.profiles[ev.pubkey] = profile
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_event(relay_id: String, conn_event: NostrConnectionEvent) {
|
||||||
switch conn_event {
|
switch conn_event {
|
||||||
case .ws_event(let ev):
|
case .ws_event(let ev):
|
||||||
switch ev {
|
switch ev {
|
||||||
case .connected:
|
case .connected:
|
||||||
let now = Int64(Date().timeIntervalSince1970)
|
// TODO: since times should be based on events from a specific relay
|
||||||
let yesterday = now - 24 * 60 * 60
|
// perhaps we could mark this in the relay pool somehow
|
||||||
let filter = NostrFilter.filter_since(yesterday)
|
|
||||||
|
let since = get_since_time(events: self.events)
|
||||||
|
let filter = NostrFilter.filter_since(since)
|
||||||
|
print("connected to \(relay_id), refreshing from \(since)")
|
||||||
let sub_id = self.sub_id ?? UUID().description
|
let sub_id = self.sub_id ?? UUID().description
|
||||||
if self.sub_id != sub_id {
|
if self.sub_id != sub_id {
|
||||||
self.sub_id = sub_id
|
self.sub_id = sub_id
|
||||||
}
|
}
|
||||||
print("subscribing to \(sub_id)")
|
print("subscribing to \(sub_id)")
|
||||||
self.connection?.send(filter, sub_id: sub_id)
|
self.pool?.send(filter: filter, sub_id: sub_id)
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
self.connection?.connect()
|
self.pool?.connect(to: [relay_id])
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -120,9 +140,16 @@ struct ContentView: View {
|
|||||||
self.loading = false
|
self.loading = false
|
||||||
}
|
}
|
||||||
self.sub_id = sub_id
|
self.sub_id = sub_id
|
||||||
if ev.kind == 1 && !(has_events[ev.id] ?? false) {
|
|
||||||
|
if !(has_events[ev.id] ?? false) {
|
||||||
has_events[ev.id] = true
|
has_events[ev.id] = true
|
||||||
|
if ev.kind == 1 {
|
||||||
self.events.append(ev)
|
self.events.append(ev)
|
||||||
|
} else if ev.kind == 0 {
|
||||||
|
handle_metadata_event(ev)
|
||||||
|
} else if ev.kind == 3 {
|
||||||
|
handle_contact_event(ev)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case .notice(let msg):
|
case .notice(let msg):
|
||||||
print(msg)
|
print(msg)
|
||||||
@ -154,3 +181,36 @@ func PostButton(action: @escaping () -> ()) -> some View {
|
|||||||
y: 3)
|
y: 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func get_since_time(events: [NostrEvent]) -> Int64 {
|
||||||
|
if events.count == 0 {
|
||||||
|
return Int64(Date().timeIntervalSince1970) - (24 * 60 * 60)
|
||||||
|
}
|
||||||
|
|
||||||
|
return events.last!.created_at - 60
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func fetch_profiles(relay: URL, pubkeys: [String]) {
|
||||||
|
return NostrFilter(ids: nil, kinds: 3, event_ids: nil, pubkeys: pubkeys, since: nil, until: nil, authors: pubkeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func nostr_req(relays: [URL], filter: NostrFilter) {
|
||||||
|
if relays.count == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let conn = NostrConnection(url: relay) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func get_profiles()
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
func add_rw_relay(_ pool: RelayPool, _ url: String) {
|
||||||
|
let url_ = URL(string: url)!
|
||||||
|
try! pool.add_relay(url_, info: RelayInfo.rw)
|
||||||
|
}
|
||||||
|
17
damus/Nostr.swift
Normal file
17
damus/Nostr.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Nostr.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2022-04-07.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
struct Profile: Decodable {
|
||||||
|
let name: String
|
||||||
|
let about: String
|
||||||
|
let picture: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ struct NostrSubscription {
|
|||||||
struct NostrFilter: Codable {
|
struct NostrFilter: Codable {
|
||||||
let ids: [String]?
|
let ids: [String]?
|
||||||
let kinds: [String]?
|
let kinds: [String]?
|
||||||
let event_ids: [String]?
|
let referenced_ids: [String]?
|
||||||
let pubkeys: [String]?
|
let pubkeys: [String]?
|
||||||
let since: Int64?
|
let since: Int64?
|
||||||
let until: Int64?
|
let until: Int64?
|
||||||
@ -45,7 +45,7 @@ struct NostrFilter: Codable {
|
|||||||
private enum CodingKeys : String, CodingKey {
|
private enum CodingKeys : String, CodingKey {
|
||||||
case ids
|
case ids
|
||||||
case kinds
|
case kinds
|
||||||
case event_ids = "#e"
|
case referenced_ids = "#e"
|
||||||
case pubkeys = "#p"
|
case pubkeys = "#p"
|
||||||
case since
|
case since
|
||||||
case until
|
case until
|
||||||
@ -53,7 +53,7 @@ struct NostrFilter: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static func filter_since(_ val: Int64) -> NostrFilter {
|
public static func filter_since(_ val: Int64) -> NostrFilter {
|
||||||
return NostrFilter(ids: nil, kinds: nil, event_ids: nil, pubkeys: nil, since: val, until: nil, authors: nil)
|
return NostrFilter(ids: nil, kinds: nil, referenced_ids: nil, pubkeys: nil, since: val, until: nil, authors: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,99 @@ struct NostrEvent: Decodable, Identifiable {
|
|||||||
let sig: String
|
let sig: String
|
||||||
}
|
}
|
||||||
|
|
||||||
class NostrConnection: WebSocketDelegate {
|
struct RelayInfo {
|
||||||
|
let read: Bool
|
||||||
|
let write: Bool
|
||||||
|
|
||||||
|
static let rw = RelayInfo(read: true, write: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Relay: Identifiable {
|
||||||
|
let url: URL
|
||||||
|
let info: RelayInfo
|
||||||
|
let connection: RelayConnection
|
||||||
|
|
||||||
|
var id: String {
|
||||||
|
return get_relay_id(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_relay_id(_ url: URL) -> String {
|
||||||
|
return url.absoluteString
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RelayError: Error {
|
||||||
|
case RelayAlreadyExists
|
||||||
|
case RelayNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
class RelayPool {
|
||||||
|
var relays: [Relay] = []
|
||||||
|
let custom_handle_event: (String, NostrConnectionEvent) -> ()
|
||||||
|
|
||||||
|
init(handle_event: @escaping (String, NostrConnectionEvent) -> ()) {
|
||||||
|
self.custom_handle_event = handle_event
|
||||||
|
}
|
||||||
|
|
||||||
|
func add_relay(_ url: URL, info: RelayInfo) throws {
|
||||||
|
let relay_id = get_relay_id(url)
|
||||||
|
if get_relay(relay_id) != nil {
|
||||||
|
throw RelayError.RelayAlreadyExists
|
||||||
|
}
|
||||||
|
let conn = RelayConnection(url: url) { event in
|
||||||
|
self.handle_event(relay_id: relay_id, event: event)
|
||||||
|
}
|
||||||
|
let relay = Relay(url: url, info: info, connection: conn)
|
||||||
|
self.relays.append(relay)
|
||||||
|
}
|
||||||
|
|
||||||
|
func connect(to: [String]? = nil) {
|
||||||
|
let relays = to.map{ get_relays($0) } ?? self.relays
|
||||||
|
for relay in relays {
|
||||||
|
relay.connection.connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(filter: NostrFilter, sub_id: String, to: [String]? = nil) {
|
||||||
|
let relays = to.map{ get_relays($0) } ?? self.relays
|
||||||
|
|
||||||
|
for relay in relays {
|
||||||
|
if relay.connection.isConnected {
|
||||||
|
relay.connection.send(filter, sub_id: sub_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_relays(_ ids: [String]) -> [Relay] {
|
||||||
|
var relays: [Relay] = []
|
||||||
|
|
||||||
|
for id in ids {
|
||||||
|
if let relay = get_relay(id) {
|
||||||
|
relays.append(relay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return relays
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_relay(_ id: String) -> Relay? {
|
||||||
|
for relay in relays {
|
||||||
|
if relay.id == id {
|
||||||
|
return relay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handle_event(relay_id: String, event: NostrConnectionEvent) {
|
||||||
|
// handle reconnect logic, etc?
|
||||||
|
custom_handle_event(relay_id, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RelayConnection: WebSocketDelegate {
|
||||||
var isConnected: Bool = false
|
var isConnected: Bool = false
|
||||||
var socket: WebSocket
|
var socket: WebSocket
|
||||||
var handleEvent: (NostrConnectionEvent) -> ()
|
var handleEvent: (NostrConnectionEvent) -> ()
|
Loading…
Reference in New Issue
Block a user