damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 603a5a18144abc98786a383356c7c39930861fec
parent 06a1a9aba6f9ee54350d9a64d6897193c2e18f23
Author: Bryan Montz <bryanmontz@me.com>
Date:   Sat, 18 Feb 2023 00:27:15 -0600

Refinements to RelayConnection plus tests for creating requests

Closes: #644

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/Nostr/NostrEvent.swift | 18++----------------
Mdamus/Nostr/RelayConnection.swift | 60++++++++++++++++++++++++++----------------------------------
AdamusTests/RequestTests.swift | 39+++++++++++++++++++++++++++++++++++++++
4 files changed, 71 insertions(+), 50 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -199,6 +199,7 @@ 4CF0ABF029857E9200D66079 /* Bech32Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABEF29857E9200D66079 /* Bech32Object.swift */; }; 4CF0ABF62985CD5500D66079 /* UserSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABF52985CD5500D66079 /* UserSearch.swift */; }; 4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; }; + 50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; }; 5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; }; 5C513FCC2984ACA60072348F /* QRCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FCB2984ACA60072348F /* QRCodeView.swift */; }; 6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439E013296790CF0020672B /* ProfileZoomView.swift */; }; @@ -513,6 +514,7 @@ 4CF0ABEF29857E9200D66079 /* Bech32Object.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Object.swift; sourceTree = "<group>"; }; 4CF0ABF52985CD5500D66079 /* UserSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSearch.swift; sourceTree = "<group>"; }; 4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; }; + 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; }; 5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = "<group>"; }; 5C513FCB2984ACA60072348F /* QRCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeView.swift; sourceTree = "<group>"; }; 6439E013296790CF0020672B /* ProfileZoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZoomView.swift; sourceTree = "<group>"; }; @@ -934,6 +936,7 @@ 4CE6DEF627F7A08200C66700 /* damusTests */ = { isa = PBXGroup; children = ( + 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */, DD597CBC2963D85A00C64D32 /* MarkdownTests.swift */, 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */, 4C363A9F2828A8DD006E126D /* LikeTests.swift */, @@ -1394,6 +1397,7 @@ 4CB883AE2976FA9300DC99E7 /* FormatTests.swift in Sources */, 4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */, 4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */, + 50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */, 4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */, 4CF0ABDC2981A19E00D66079 /* ListTests.swift in Sources */, ); diff --git a/damus/Nostr/NostrEvent.swift b/damus/Nostr/NostrEvent.swift @@ -278,21 +278,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has return (self.flags & 1) != 0 } - init(content: String, pubkey: String, kind: Int = 1, tags: [[String]] = [], createdAt: Int64 = Int64(Date().timeIntervalSince1970)) { - self.id = "" - self.sig = "" - - self.content = content - self.pubkey = pubkey - self.kind = kind - self.tags = tags - self.created_at = createdAt - } - - /// Intiialization statement used to specificy ID - /// - /// This is mainly used for contant and testing data - init(id: String, content: String, pubkey: String, kind: Int = 1, tags: [[String]] = []) { + init(id: String = "", content: String, pubkey: String, kind: Int = 1, tags: [[String]] = [], createdAt: Int64 = Int64(Date().timeIntervalSince1970)) { self.id = id self.sig = "" @@ -300,7 +286,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has self.pubkey = pubkey self.kind = kind self.tags = tags - self.created_at = Int64(Date().timeIntervalSince1970) + self.created_at = createdAt } init(from: NostrEvent, content: String? = nil) { diff --git a/damus/Nostr/RelayConnection.swift b/damus/Nostr/RelayConnection.swift @@ -13,42 +13,41 @@ enum NostrConnectionEvent { case nostr_event(NostrResponse) } -class RelayConnection: WebSocketDelegate { - var isConnected: Bool = false - var isConnecting: Bool = false - var isReconnecting: Bool = false - var last_connection_attempt: Double = 0 - var socket: WebSocket - var handleEvent: (NostrConnectionEvent) -> () - let url: URL +final class RelayConnection: WebSocketDelegate { + private(set) var isConnected = false + private(set) var isConnecting = false + private(set) var isReconnecting = false + + private(set) var last_connection_attempt: TimeInterval = 0 + private lazy var socket = { + let req = URLRequest(url: url) + let socket = WebSocket(request: req, compressionHandler: .none) + socket.delegate = self + return socket + }() + private var handleEvent: (NostrConnectionEvent) -> () + private let url: URL init(url: URL, handleEvent: @escaping (NostrConnectionEvent) -> ()) { self.url = url self.handleEvent = handleEvent - // just init, we don't actually use this one - self.socket = make_websocket(url: url) } func reconnect() { - if self.isConnected { - self.isReconnecting = true - self.disconnect() + if isConnected { + isReconnecting = true + disconnect() } else { // we're already disconnected, so just connect - self.connect(force: true) + connect(force: true) } } - func connect(force: Bool = false){ - if !force && (self.isConnected || self.isConnecting) { + func connect(force: Bool = false) { + if !force && (isConnected || isConnecting) { return } - - var req = URLRequest(url: self.url) - req.timeoutInterval = 5 - socket = make_websocket(url: url) - socket.delegate = self - + isConnecting = true last_connection_attempt = Date().timeIntervalSince1970 socket.connect() @@ -68,7 +67,9 @@ class RelayConnection: WebSocketDelegate { socket.write(string: req) } - + + // MARK: - WebSocketDelegate + func didReceive(event: WebSocketEvent, client: WebSocket) { switch event { case .connected: @@ -83,8 +84,7 @@ class RelayConnection: WebSocketDelegate { self.connect() } - case .cancelled: fallthrough - case .error: + case .cancelled, .error: self.isConnecting = false self.isConnected = false @@ -114,7 +114,6 @@ class RelayConnection: WebSocketDelegate { handleEvent(.ws_event(event)) } - } func make_nostr_req(_ req: NostrRequest) -> String? { @@ -138,7 +137,7 @@ func make_nostr_push_event(ev: NostrEvent) -> String? { } func make_nostr_unsubscribe_req(_ sub_id: String) -> String? { - return "[\"CLOSE\",\"\(sub_id)\"]" + "[\"CLOSE\",\"\(sub_id)\"]" } func make_nostr_subscription_req(_ filters: [NostrFilter], sub_id: String) -> String? { @@ -155,10 +154,3 @@ func make_nostr_subscription_req(_ filters: [NostrFilter], sub_id: String) -> St req += "]" return req } - -func make_websocket(url: URL) -> WebSocket { - let req = URLRequest(url: url) - //req.setValue("chat,superchat", forHTTPHeaderField: "Sec-WebSocket-Protocol") - return WebSocket(request: req, compressionHandler: .none) -} - diff --git a/damusTests/RequestTests.swift b/damusTests/RequestTests.swift @@ -0,0 +1,39 @@ +// +// RequestTests.swift +// damusTests +// +// Created by Bryan Montz on 2/17/23. +// + +import XCTest +@testable import damus + +final class RequestTests: XCTestCase { + + func testMakeUnsubscribeRequest() { + let request = NostrRequest.unsubscribe("64FD064D-EB9E-4771-8255-8D16981B920B") + let result = make_nostr_req(request) + let expectedResult = "[\"CLOSE\",\"64FD064D-EB9E-4771-8255-8D16981B920B\"]" + XCTAssertEqual(result, expectedResult) + } + + func testMakePushEvent() { + let now = Int64(Date().timeIntervalSince1970) + let event = NostrEvent(id: "59c1cf11a3e9e128c6fd5402f41e8ae0c0c7fbab570203d7410518be68c3115f", + content: "Testing", + pubkey: "d9fa34214aa9d151c4f4db843e9c2af4f246bab4205137731f91bcfa44d66a62", + kind: 1, + createdAt: now) + let result = make_nostr_req(.event(event)) + let expectedResult = "[\"EVENT\",{\"pubkey\":\"d9fa34214aa9d151c4f4db843e9c2af4f246bab4205137731f91bcfa44d66a62\",\"content\":\"Testing\",\"id\":\"59c1cf11a3e9e128c6fd5402f41e8ae0c0c7fbab570203d7410518be68c3115f\",\"created_at\":\(now),\"sig\":\"\",\"kind\":1,\"tags\":[]}]" + XCTAssertEqual(result, expectedResult) + } + + func testMakeSubscriptionRequest() { + let filter = NostrFilter(kinds: [3], limit: 1, authors: ["d9fa34214aa9d151c4f4db843e9c2af4f246bab4205137731f91bcfa44d66a62"]) + let subscribe = NostrSubscribe(filters: [filter], sub_id: "31C737B7-C8F9-41DD-8707-325974F279A4") + let result = make_nostr_req(.subscribe(subscribe)) + let expectedResult = "[\"REQ\",\"31C737B7-C8F9-41DD-8707-325974F279A4\",{\"kinds\":[3],\"authors\":[\"d9fa34214aa9d151c4f4db843e9c2af4f246bab4205137731f91bcfa44d66a62\"],\"limit\":1}]" + XCTAssertEqual(result, expectedResult) + } +}