From b83065e48690d6a606b3aa2d27dfa55083fac0a6 Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Fri, 23 Sep 2022 19:03:48 +0300 Subject: [PATCH] Revert "Merge pull request #506 from WalletConnect/feature/relay-retry" This reverts commit e583fea877cd624951a4d5c57c67f060be820eff, reversing changes made to 93bef419614c215055da70219f4d2069443f49b5. --- Example/ExampleApp/SceneDelegate.swift | 12 ++- Sources/WalletConnectRelay/Dispatching.swift | 82 ++++++++----------- Sources/WalletConnectRelay/RelayClient.swift | 16 ++-- Tests/RelayerTests/DispatcherTests.swift | 15 ++-- Tests/RelayerTests/Mocks/DispatcherMock.swift | 28 ++----- 5 files changed, 67 insertions(+), 86 deletions(-) diff --git a/Example/ExampleApp/SceneDelegate.swift b/Example/ExampleApp/SceneDelegate.swift index f52c84ae63..f1e41b958b 100644 --- a/Example/ExampleApp/SceneDelegate.swift +++ b/Example/ExampleApp/SceneDelegate.swift @@ -45,8 +45,16 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { return } let wcUri = incomingURL.absoluteString.deletingPrefix("https://walletconnect.com/wc?uri=") - Task(priority: .high) { - try! await Sign.instance.pair(uri: WalletConnectURI(string: wcUri)!) + let vc = ((window!.rootViewController as! UINavigationController).viewControllers[0] as! WalletViewController) + Task(priority: .high) {try? await Sign.instance.pair(uri: WalletConnectURI(string: wcUri)!)} + vc.onClientConnected = { + Task(priority: .high) { + do { + try await Sign.instance.pair(uri: WalletConnectURI(string: wcUri)!) + } catch { + print(error) + } + } } } } diff --git a/Sources/WalletConnectRelay/Dispatching.swift b/Sources/WalletConnectRelay/Dispatching.swift index 6df8a56f42..2d8be9ba5f 100644 --- a/Sources/WalletConnectRelay/Dispatching.swift +++ b/Sources/WalletConnectRelay/Dispatching.swift @@ -1,31 +1,25 @@ import Foundation -import Combine import WalletConnectUtils protocol Dispatching { - var onMessage: ((String) -> Void)? { get set } - var socketConnectionStatusPublisher: AnyPublisher { get } + var onConnect: (() -> Void)? {get set} + var onDisconnect: (() -> Void)? {get set} + var onMessage: ((String) -> Void)? {get set} + func send(_ string: String) async throws func send(_ string: String, completion: @escaping (Error?) -> Void) - func protectedSend(_ string: String, completion: @escaping (Error?) -> Void) - func protectedSend(_ string: String) async throws func connect() throws func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws } final class Dispatcher: NSObject, Dispatching { + var onConnect: (() -> Void)? + var onDisconnect: (() -> Void)? var onMessage: ((String) -> Void)? + private var textFramesQueue = Queue() + private let logger: ConsoleLogging var socket: WebSocketConnecting var socketConnectionHandler: SocketConnectionHandler - private let logger: ConsoleLogging - private let defaultTimeout: Int = 5 - - private let socketConnectionStatusPublisherSubject = PassthroughSubject() - - var socketConnectionStatusPublisher: AnyPublisher { - socketConnectionStatusPublisherSubject.eraseToAnyPublisher() - } - init(socket: WebSocketConnecting, socketConnectionHandler: SocketConnectionHandler, logger: ConsoleLogging) { @@ -37,43 +31,28 @@ final class Dispatcher: NSObject, Dispatching { setUpSocketConnectionObserving() } + func send(_ string: String) async throws { + return try await withCheckedThrowingContinuation { continuation in + if socket.isConnected { + socket.write(string: string) { + continuation.resume(returning: ()) + } + } else { + continuation.resume(throwing: NetworkError.webSocketNotConnected) + } + } + } + func send(_ string: String, completion: @escaping (Error?) -> Void) { + // TODO - add policy for retry and "single try" if socket.isConnected { self.socket.write(string: string) { completion(nil) } + // TODO - enqueue if fails } else { completion(NetworkError.webSocketNotConnected) - } - } - - func protectedSend(_ string: String, completion: @escaping (Error?) -> Void) { - guard !socket.isConnected else { - return send(string, completion: completion) - } - - var cancellable: AnyCancellable? - cancellable = socketConnectionStatusPublisher.sink { [unowned self] status in - guard status == .connected else { return } - cancellable?.cancel() - send(string, completion: completion) - } - - DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(defaultTimeout)) { - completion(NetworkError.webSocketNotConnected) - cancellable?.cancel() - } - } - - func protectedSend(_ string: String) async throws { - return try await withCheckedThrowingContinuation { continuation in - protectedSend(string) { error in - if let error = error { - continuation.resume(throwing: error) - } else { - continuation.resume(returning: ()) - } - } +// textFramesQueue.enqueue(string) } } @@ -93,10 +72,21 @@ final class Dispatcher: NSObject, Dispatching { private func setUpSocketConnectionObserving() { socket.onConnect = { [unowned self] in - self.socketConnectionStatusPublisherSubject.send(.connected) + self.dequeuePendingTextFrames() + self.onConnect?() } socket.onDisconnect = { [unowned self] _ in - self.socketConnectionStatusPublisherSubject.send(.disconnected) + self.onDisconnect?() + } + } + + private func dequeuePendingTextFrames() { + while let frame = textFramesQueue.dequeue() { + send(frame) { [unowned self] error in + if let error = error { + self.logger.error(error.localizedDescription) + } + } } } } diff --git a/Sources/WalletConnectRelay/RelayClient.swift b/Sources/WalletConnectRelay/RelayClient.swift index 9aa2ba8a47..fedd95d2e2 100644 --- a/Sources/WalletConnectRelay/RelayClient.swift +++ b/Sources/WalletConnectRelay/RelayClient.swift @@ -28,10 +28,11 @@ public final class RelayClient { } public var socketConnectionStatusPublisher: AnyPublisher { - dispatcher.socketConnectionStatusPublisher + socketConnectionStatusPublisherSubject.eraseToAnyPublisher() } private let messagePublisherSubject = PassthroughSubject<(topic: String, message: String), Never>() + private let socketConnectionStatusPublisherSubject = PassthroughSubject() private let subscriptionResponsePublisherSubject = PassthroughSubject<(RPCID?, String), Never>() private var subscriptionResponsePublisher: AnyPublisher<(RPCID?, String), Never> { @@ -65,6 +66,9 @@ public final class RelayClient { dispatcher.onMessage = { [weak self] payload in self?.handlePayloadMessage(payload) } + dispatcher.onConnect = { [unowned self] in + self.socketConnectionStatusPublisherSubject.send(.connected) + } } /// Instantiates Relay Client @@ -126,7 +130,7 @@ public final class RelayClient { .asRPCRequest() let message = try request.asJSONEncodedString() logger.debug("Publishing payload on topic: \(topic)") - try await dispatcher.protectedSend(message) + try await dispatcher.send(message) } /// Completes with an acknowledgement from the relay network. @@ -150,7 +154,7 @@ public final class RelayClient { cancellable?.cancel() onNetworkAcknowledge(nil) } - dispatcher.protectedSend(message) { [weak self] error in + dispatcher.send(message) { [weak self] error in if let error = error { self?.logger.debug("Failed to Publish Payload, error: \(error)") cancellable?.cancel() @@ -177,7 +181,7 @@ public final class RelayClient { } completion(nil) } - dispatcher.protectedSend(message) { [weak self] error in + dispatcher.send(message) { [weak self] error in if let error = error { self?.logger.debug("Failed to subscribe to topic \(error)") cancellable?.cancel() @@ -217,7 +221,7 @@ public final class RelayClient { cancellable?.cancel() completion(nil) } - dispatcher.protectedSend(message) { [weak self] error in + dispatcher.send(message) { [weak self] error in if let error = error { self?.logger.debug("Failed to unsubscribe from topic") cancellable?.cancel() @@ -273,7 +277,7 @@ public final class RelayClient { private func acknowledgeRequest(_ request: RPCRequest) throws { let response = RPCResponse(matchingRequest: request, result: true) let message = try response.asJSONEncodedString() - dispatcher.protectedSend(message) { [unowned self] in + dispatcher.send(message) { [unowned self] in if let error = $0 { logger.debug("Failed to dispatch response: \(response), error: \(error)") } else { diff --git a/Tests/RelayerTests/DispatcherTests.swift b/Tests/RelayerTests/DispatcherTests.swift index 9d32b380d2..78103a30c4 100644 --- a/Tests/RelayerTests/DispatcherTests.swift +++ b/Tests/RelayerTests/DispatcherTests.swift @@ -1,6 +1,5 @@ import Foundation import XCTest -import Combine @testable import WalletConnectRelay import TestingUtils import Combine @@ -30,7 +29,6 @@ class WebSocketMock: WebSocketConnecting { } final class DispatcherTests: XCTestCase { - var publishers = Set() var sut: Dispatcher! var webSocket: WebSocketMock! var networkMonitor: NetworkMonitoringMock! @@ -68,21 +66,18 @@ final class DispatcherTests: XCTestCase { func testOnConnect() { let expectation = expectation(description: "on connect") - sut.socketConnectionStatusPublisher.sink { status in - guard status == .connected else { return } + sut.onConnect = { expectation.fulfill() - }.store(in: &publishers) + } webSocket.onConnect?() waitForExpectations(timeout: 0.001) } - func testOnDisconnect() throws { + func testOnDisconnect() { let expectation = expectation(description: "on disconnect") - try sut.connect() - sut.socketConnectionStatusPublisher.sink { status in - guard status == .disconnected else { return } + sut.onDisconnect = { expectation.fulfill() - }.store(in: &publishers) + } webSocket.onDisconnect?(nil) waitForExpectations(timeout: 0.001) } diff --git a/Tests/RelayerTests/Mocks/DispatcherMock.swift b/Tests/RelayerTests/Mocks/DispatcherMock.swift index d5088bf61e..97ddac5dca 100644 --- a/Tests/RelayerTests/Mocks/DispatcherMock.swift +++ b/Tests/RelayerTests/Mocks/DispatcherMock.swift @@ -1,34 +1,18 @@ import Foundation import JSONRPC -import Combine @testable import WalletConnectRelay class DispatcherMock: Dispatching { - private var publishers = Set() - private let socketConnectionStatusPublisherSubject = CurrentValueSubject(.disconnected) - var socketConnectionStatusPublisher: AnyPublisher { - return socketConnectionStatusPublisherSubject.eraseToAnyPublisher() - } - var sent = false - var lastMessage: String = "" + var onConnect: (() -> Void)? + var onDisconnect: (() -> Void)? var onMessage: ((String) -> Void)? - func protectedSend(_ string: String, completion: @escaping (Error?) -> Void) { - send(string, completion: completion) - } - - func protectedSend(_ string: String) async throws { - try await send(string) - } + func connect() {} + func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) {} - func connect() { - socketConnectionStatusPublisherSubject.send(.connected) - } - - func disconnect(closeCode: URLSessionWebSocketTask.CloseCode) { - socketConnectionStatusPublisherSubject.send(.disconnected) - } + var sent = false + var lastMessage: String = "" func send(_ string: String, completion: @escaping (Error?) -> Void) { sent = true