From b5f4f137834233efd5c190f797511cae6ada5514 Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Thu, 1 Sep 2022 18:28:04 +0300 Subject: [PATCH 01/13] NetworkInteracting moved to package --- Package.swift | 9 +++++++- .../Auth/Services/App/AppPairService.swift | 1 + .../Auth/Services/App/AppRequestService.swift | 3 ++- .../Services/App/AppRespondSubscriber.swift | 5 +++-- .../Common/NetworkingInteractor.swift | 22 +++---------------- .../Services/Wallet/WalletPairService.swift | 1 + .../Wallet/WalletRequestSubscriber.swift | 5 +++-- .../Wallet/WalletRespondService.swift | 3 ++- Sources/Auth/Types/Errors/AuthError.swift | 1 + .../Types/RequestSubscriptionPayload.swift | 7 ------ .../Types/ResponseSubscriptionPayload.swift | 7 ------ .../NetworkInteractor.swift | 21 ++++++++++++++++++ .../Reason.swift | 2 +- .../RequestSubscriptionPayload.swift | 12 ++++++++++ .../ResponseSubscriptionPayload.swift | 12 ++++++++++ .../AuthTests/AppRespondSubscriberTests.swift | 1 + .../Mocks/NetworkingInteractorMock.swift | 1 + .../Stubs/RequestSubscriptionPayload.swift | 3 ++- .../WalletRequestSubscriberTests.swift | 5 +++-- 19 files changed, 77 insertions(+), 44 deletions(-) delete mode 100644 Sources/Auth/Types/RequestSubscriptionPayload.swift delete mode 100644 Sources/Auth/Types/ResponseSubscriptionPayload.swift create mode 100644 Sources/WalletConnectNetworking/NetworkInteractor.swift rename Sources/{Auth/Types/Errors => WalletConnectNetworking}/Reason.swift (75%) create mode 100644 Sources/WalletConnectNetworking/RequestSubscriptionPayload.swift create mode 100644 Sources/WalletConnectNetworking/ResponseSubscriptionPayload.swift diff --git a/Package.swift b/Package.swift index 9c3cd5b68..6e0da39f7 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,10 @@ let package = Package( targets: ["Auth"]), .library( name: "WalletConnectRouter", - targets: ["WalletConnectRouter"]) + targets: ["WalletConnectRouter"]), + .library( + name: "WalletConnectNetworking", + targets: ["WalletConnectNetworking"]), ], dependencies: [ .package(url: "https://github.com/flypaper0/Web3.swift", .branch("feature/eip-155")) @@ -42,6 +45,7 @@ let package = Package( "WalletConnectUtils", "WalletConnectKMS", "WalletConnectPairing", + "WalletConnectNetworking", .product(name: "Web3", package: "Web3.swift") ], path: "Sources/Auth"), @@ -65,6 +69,9 @@ let package = Package( .target( name: "Commons", dependencies: []), + .target( + name: "WalletConnectNetworking", + dependencies: ["JSONRPC", "WalletConnectKMS"]), .target( name: "WalletConnectRouter", dependencies: []), diff --git a/Sources/Auth/Services/App/AppPairService.swift b/Sources/Auth/Services/App/AppPairService.swift index 1dc9c0cbc..dc05600b0 100644 --- a/Sources/Auth/Services/App/AppPairService.swift +++ b/Sources/Auth/Services/App/AppPairService.swift @@ -1,6 +1,7 @@ import Foundation import WalletConnectKMS import WalletConnectPairing +import WalletConnectNetworking actor AppPairService { private let networkingInteractor: NetworkInteracting diff --git a/Sources/Auth/Services/App/AppRequestService.swift b/Sources/Auth/Services/App/AppRequestService.swift index b3186e77d..9303d7bb8 100644 --- a/Sources/Auth/Services/App/AppRequestService.swift +++ b/Sources/Auth/Services/App/AppRequestService.swift @@ -1,7 +1,8 @@ import Foundation +import JSONRPC +import WalletConnectNetworking import WalletConnectUtils import WalletConnectKMS -import JSONRPC actor AppRequestService { private let networkingInteractor: NetworkInteracting diff --git a/Sources/Auth/Services/App/AppRespondSubscriber.swift b/Sources/Auth/Services/App/AppRespondSubscriber.swift index 3a501b718..16e0ff807 100644 --- a/Sources/Auth/Services/App/AppRespondSubscriber.swift +++ b/Sources/Auth/Services/App/AppRespondSubscriber.swift @@ -1,7 +1,8 @@ -import Combine import Foundation -import WalletConnectUtils +import Combine import JSONRPC +import WalletConnectNetworking +import WalletConnectUtils import WalletConnectPairing class AppRespondSubscriber { diff --git a/Sources/Auth/Services/Common/NetworkingInteractor.swift b/Sources/Auth/Services/Common/NetworkingInteractor.swift index e66e97a77..b1cc7684a 100644 --- a/Sources/Auth/Services/Common/NetworkingInteractor.swift +++ b/Sources/Auth/Services/Common/NetworkingInteractor.swift @@ -1,26 +1,10 @@ import Foundation +import Combine +import JSONRPC +import WalletConnectNetworking import WalletConnectRelay import WalletConnectUtils -import Combine import WalletConnectKMS -import JSONRPC - -protocol NetworkInteracting { - var requestPublisher: AnyPublisher {get} - var responsePublisher: AnyPublisher {get} - func subscribe(topic: String) async throws - func unsubscribe(topic: String) - func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws - func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws - func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws - func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws -} - -extension NetworkInteracting { - func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType = .type0) async throws { - try await self.request(request, topic: topic, tag: tag, envelopeType: envelopeType) - } -} class NetworkingInteractor: NetworkInteracting { private var publishers = Set() diff --git a/Sources/Auth/Services/Wallet/WalletPairService.swift b/Sources/Auth/Services/Wallet/WalletPairService.swift index ef4fc2e28..355de0a29 100644 --- a/Sources/Auth/Services/Wallet/WalletPairService.swift +++ b/Sources/Auth/Services/Wallet/WalletPairService.swift @@ -1,6 +1,7 @@ import Foundation import WalletConnectKMS import WalletConnectPairing +import WalletConnectNetworking actor WalletPairService { enum Errors: Error { diff --git a/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift b/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift index 522820187..c54bd3935 100644 --- a/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift +++ b/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift @@ -1,7 +1,8 @@ -import Combine import Foundation -import WalletConnectUtils +import Combine import JSONRPC +import WalletConnectNetworking +import WalletConnectUtils import WalletConnectKMS class WalletRequestSubscriber { diff --git a/Sources/Auth/Services/Wallet/WalletRespondService.swift b/Sources/Auth/Services/Wallet/WalletRespondService.swift index 07e01871c..9107f4df3 100644 --- a/Sources/Auth/Services/Wallet/WalletRespondService.swift +++ b/Sources/Auth/Services/Wallet/WalletRespondService.swift @@ -1,7 +1,8 @@ import Foundation -import WalletConnectKMS import JSONRPC +import WalletConnectKMS import WalletConnectUtils +import WalletConnectNetworking actor WalletRespondService { enum Errors: Error { diff --git a/Sources/Auth/Types/Errors/AuthError.swift b/Sources/Auth/Types/Errors/AuthError.swift index 84c43a7d0..f28cab817 100644 --- a/Sources/Auth/Types/Errors/AuthError.swift +++ b/Sources/Auth/Types/Errors/AuthError.swift @@ -1,4 +1,5 @@ import Foundation +import WalletConnectNetworking /// Authentication error public enum AuthError: Codable, Equatable, Error { diff --git a/Sources/Auth/Types/RequestSubscriptionPayload.swift b/Sources/Auth/Types/RequestSubscriptionPayload.swift deleted file mode 100644 index 00a5cdcb4..000000000 --- a/Sources/Auth/Types/RequestSubscriptionPayload.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation -import JSONRPC - -struct RequestSubscriptionPayload: Codable, Equatable { - let topic: String - let request: RPCRequest -} diff --git a/Sources/Auth/Types/ResponseSubscriptionPayload.swift b/Sources/Auth/Types/ResponseSubscriptionPayload.swift deleted file mode 100644 index d6425622f..000000000 --- a/Sources/Auth/Types/ResponseSubscriptionPayload.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation -import JSONRPC - -struct ResponseSubscriptionPayload: Codable, Equatable { - let topic: String - let response: RPCResponse -} diff --git a/Sources/WalletConnectNetworking/NetworkInteractor.swift b/Sources/WalletConnectNetworking/NetworkInteractor.swift new file mode 100644 index 000000000..668448236 --- /dev/null +++ b/Sources/WalletConnectNetworking/NetworkInteractor.swift @@ -0,0 +1,21 @@ +import Foundation +import Combine +import JSONRPC +import WalletConnectKMS + +public protocol NetworkInteracting { + var requestPublisher: AnyPublisher {get} + var responsePublisher: AnyPublisher {get} + func subscribe(topic: String) async throws + func unsubscribe(topic: String) + func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws + func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws + func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws + func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws +} + +extension NetworkInteracting { + public func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType = .type0) async throws { + try await self.request(request, topic: topic, tag: tag, envelopeType: envelopeType) + } +} diff --git a/Sources/Auth/Types/Errors/Reason.swift b/Sources/WalletConnectNetworking/Reason.swift similarity index 75% rename from Sources/Auth/Types/Errors/Reason.swift rename to Sources/WalletConnectNetworking/Reason.swift index 4822fe64c..b9b26694f 100644 --- a/Sources/Auth/Types/Errors/Reason.swift +++ b/Sources/WalletConnectNetworking/Reason.swift @@ -1,6 +1,6 @@ import Foundation -protocol Reason { +public protocol Reason { var code: Int { get } var message: String { get } } diff --git a/Sources/WalletConnectNetworking/RequestSubscriptionPayload.swift b/Sources/WalletConnectNetworking/RequestSubscriptionPayload.swift new file mode 100644 index 000000000..6132f19a2 --- /dev/null +++ b/Sources/WalletConnectNetworking/RequestSubscriptionPayload.swift @@ -0,0 +1,12 @@ +import Foundation +import JSONRPC + +public struct RequestSubscriptionPayload: Codable, Equatable { + public let topic: String + public let request: RPCRequest + + public init(topic: String, request: RPCRequest) { + self.topic = topic + self.request = request + } +} diff --git a/Sources/WalletConnectNetworking/ResponseSubscriptionPayload.swift b/Sources/WalletConnectNetworking/ResponseSubscriptionPayload.swift new file mode 100644 index 000000000..cfe2e6ab2 --- /dev/null +++ b/Sources/WalletConnectNetworking/ResponseSubscriptionPayload.swift @@ -0,0 +1,12 @@ +import Foundation +import JSONRPC + +public struct ResponseSubscriptionPayload: Codable, Equatable { + public let topic: String + public let response: RPCResponse + + public init(topic: String, response: RPCResponse) { + self.topic = topic + self.response = response + } +} diff --git a/Tests/AuthTests/AppRespondSubscriberTests.swift b/Tests/AuthTests/AppRespondSubscriberTests.swift index a5eb20c2f..95f5807db 100644 --- a/Tests/AuthTests/AppRespondSubscriberTests.swift +++ b/Tests/AuthTests/AppRespondSubscriberTests.swift @@ -2,6 +2,7 @@ import Foundation import XCTest @testable import Auth import WalletConnectUtils +import WalletConnectNetworking @testable import WalletConnectKMS @testable import TestingUtils import JSONRPC diff --git a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift index 1a9c03790..5c9664d03 100644 --- a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift +++ b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift @@ -3,6 +3,7 @@ import Combine @testable import Auth import JSONRPC import WalletConnectKMS +import WalletConnectNetworking struct NetworkingInteractorMock: NetworkInteracting { diff --git a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift index 48ded537d..156780d42 100644 --- a/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift +++ b/Tests/AuthTests/Stubs/RequestSubscriptionPayload.swift @@ -1,6 +1,7 @@ import Foundation -@testable import Auth import JSONRPC +import WalletConnectNetworking +@testable import Auth extension RequestSubscriptionPayload { static func stub(id: RPCID) -> RequestSubscriptionPayload { diff --git a/Tests/AuthTests/WalletRequestSubscriberTests.swift b/Tests/AuthTests/WalletRequestSubscriberTests.swift index bce269680..00e7f62ee 100644 --- a/Tests/AuthTests/WalletRequestSubscriberTests.swift +++ b/Tests/AuthTests/WalletRequestSubscriberTests.swift @@ -1,10 +1,11 @@ import Foundation import XCTest -@testable import Auth +import JSONRPC import WalletConnectUtils +import WalletConnectNetworking +@testable import Auth @testable import WalletConnectKMS @testable import TestingUtils -import JSONRPC class WalletRequestSubscriberTests: XCTestCase { var networkingInteractor: NetworkingInteractorMock! From fca1b495d002b5f22a2402c30f4c24e0afdc416a Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Thu, 1 Sep 2022 18:41:10 +0300 Subject: [PATCH 02/13] Auth NetworkInteractor moved to package --- Package.swift | 10 ++++--- Sources/Auth/AuthClientFactory.swift | 1 + .../NetworkingInteractor.swift | 30 ++++++++++--------- 3 files changed, 23 insertions(+), 18 deletions(-) rename Sources/{Auth/Services/Common => WalletConnectNetworking}/NetworkingInteractor.swift (82%) diff --git a/Package.swift b/Package.swift index 6e0da39f7..1578731af 100644 --- a/Package.swift +++ b/Package.swift @@ -41,9 +41,6 @@ let package = Package( .target( name: "Auth", dependencies: [ - "WalletConnectRelay", - "WalletConnectUtils", - "WalletConnectKMS", "WalletConnectPairing", "WalletConnectNetworking", .product(name: "Web3", package: "Web3.swift") @@ -71,7 +68,12 @@ let package = Package( dependencies: []), .target( name: "WalletConnectNetworking", - dependencies: ["JSONRPC", "WalletConnectKMS"]), + dependencies: [ + "JSONRPC", + "WalletConnectKMS", + "WalletConnectRelay", + "WalletConnectUtils", + ]), .target( name: "WalletConnectRouter", dependencies: []), diff --git a/Sources/Auth/AuthClientFactory.swift b/Sources/Auth/AuthClientFactory.swift index 3dc48fbea..b084a1846 100644 --- a/Sources/Auth/AuthClientFactory.swift +++ b/Sources/Auth/AuthClientFactory.swift @@ -3,6 +3,7 @@ import WalletConnectRelay import WalletConnectUtils import WalletConnectKMS import WalletConnectPairing +import WalletConnectNetworking public struct AuthClientFactory { diff --git a/Sources/Auth/Services/Common/NetworkingInteractor.swift b/Sources/WalletConnectNetworking/NetworkingInteractor.swift similarity index 82% rename from Sources/Auth/Services/Common/NetworkingInteractor.swift rename to Sources/WalletConnectNetworking/NetworkingInteractor.swift index b1cc7684a..91a664578 100644 --- a/Sources/Auth/Services/Common/NetworkingInteractor.swift +++ b/Sources/WalletConnectNetworking/NetworkingInteractor.swift @@ -1,12 +1,11 @@ import Foundation import Combine import JSONRPC -import WalletConnectNetworking import WalletConnectRelay import WalletConnectUtils import WalletConnectKMS -class NetworkingInteractor: NetworkInteracting { +public class NetworkingInteractor: NetworkInteracting { private var publishers = Set() private let relayClient: RelayClient private let serializer: Serializing @@ -14,21 +13,24 @@ class NetworkingInteractor: NetworkInteracting { private let logger: ConsoleLogging private let requestPublisherSubject = PassthroughSubject() - var requestPublisher: AnyPublisher { + private let responsePublisherSubject = PassthroughSubject() + + public var requestPublisher: AnyPublisher { requestPublisherSubject.eraseToAnyPublisher() } - private let responsePublisherSubject = PassthroughSubject() - var responsePublisher: AnyPublisher { + public var responsePublisher: AnyPublisher { responsePublisherSubject.eraseToAnyPublisher() } - var socketConnectionStatusPublisher: AnyPublisher + public var socketConnectionStatusPublisher: AnyPublisher - init(relayClient: RelayClient, + public init( + relayClient: RelayClient, serializer: Serializing, logger: ConsoleLogging, - rpcHistory: RPCHistory) { + rpcHistory: RPCHistory + ) { self.relayClient = relayClient self.serializer = serializer self.rpcHistory = rpcHistory @@ -40,11 +42,11 @@ class NetworkingInteractor: NetworkInteracting { .store(in: &publishers) } - func subscribe(topic: String) async throws { + public func subscribe(topic: String) async throws { try await relayClient.subscribe(topic: topic) } - func unsubscribe(topic: String) { + public func unsubscribe(topic: String) { relayClient.unsubscribe(topic: topic) { [unowned self] error in if let error = error { logger.error(error) @@ -54,7 +56,7 @@ class NetworkingInteractor: NetworkInteracting { } } - func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { + public func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { try rpcHistory.set(request, forTopic: topic, emmitedBy: .local) let message = try! serializer.serialize(topic: topic, encodable: request, envelopeType: envelopeType) try await relayClient.publish(topic: topic, payload: message, tag: tag) @@ -63,7 +65,7 @@ class NetworkingInteractor: NetworkInteracting { /// Completes with an acknowledgement from the relay network. /// completes with error if networking client was not able to send a message /// TODO - relay client should provide async function - continualion should be removed from here - func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws { + public func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws { do { try rpcHistory.set(request, forTopic: topic, emmitedBy: .local) let message = try serializer.serialize(topic: topic, encodable: request) @@ -81,13 +83,13 @@ class NetworkingInteractor: NetworkInteracting { } } - func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { + public func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { try rpcHistory.resolve(response) let message = try! serializer.serialize(topic: topic, encodable: response, envelopeType: envelopeType) try await relayClient.publish(topic: topic, payload: message, tag: tag) } - func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws { + public func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws { let error = JSONRPCError(code: reason.code, message: reason.message) let response = RPCResponse(id: requestId, error: error) let message = try! serializer.serialize(topic: topic, encodable: response, envelopeType: envelopeType) From 8cef57d7d81cf3c938c01cf5259c3e6d149ec2e9 Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Thu, 1 Sep 2022 22:24:12 +0300 Subject: [PATCH 03/13] Chat Genaric interactor connected --- .../xcschemes/WalletConnectChat.xcscheme | 77 +++++++++++ Package.swift | 17 +-- Sources/Auth/AuthClientFactory.swift | 3 +- Sources/Chat/ChatClient.swift | 7 +- Sources/Chat/ChatClientFactory.swift | 10 +- Sources/Chat/NetworkingInteractor.swift | 122 ------------------ .../Chat/ProtocolServices/Common/File.swift | 4 +- .../Common/MessagingService.swift | 44 +++---- .../Invitee/InvitationHandlingService.swift | 64 ++++----- .../Invitee/RegistryService.swift | 1 + .../Inviter/InviteService.swift | 56 ++++---- Sources/Chat/Types/ChatError.swift | 15 +++ Sources/Chat/Types/ChatRequestParams.swift | 63 --------- Sources/Chat/Types/ChatResponse.swift | 9 -- .../{InviteParams.swift => Invite.swift} | 8 ++ Sources/Chat/Types/Message.swift | 22 +++- .../Types/RequestSubscriptionPayload.swift | 7 - .../NetworkInteractor.swift | 23 +++- .../NetworkingInteractor.swift | 14 +- .../Mocks/NetworkingInteractorMock.swift | 44 ------- .../Mocks/NetworkingInteractorMock.swift | 50 ------- Tests/ChatTests/RegistryManagerTests.swift | 5 +- .../NetworkingInteractorMock.swift | 58 +++++++++ 23 files changed, 298 insertions(+), 425 deletions(-) create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/WalletConnectChat.xcscheme delete mode 100644 Sources/Chat/NetworkingInteractor.swift delete mode 100644 Sources/Chat/Types/ChatRequestParams.swift delete mode 100644 Sources/Chat/Types/ChatResponse.swift rename Sources/Chat/Types/{InviteParams.swift => Invite.swift} (71%) delete mode 100644 Sources/Chat/Types/RequestSubscriptionPayload.swift delete mode 100644 Tests/AuthTests/Mocks/NetworkingInteractorMock.swift delete mode 100644 Tests/ChatTests/Mocks/NetworkingInteractorMock.swift create mode 100644 Tests/TestingUtils/NetworkingInteractorMock.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectChat.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectChat.xcscheme new file mode 100644 index 000000000..c04003b78 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectChat.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package.swift b/Package.swift index 1578731af..a562eca58 100644 --- a/Package.swift +++ b/Package.swift @@ -36,15 +36,11 @@ let package = Package( path: "Sources/WalletConnectSign"), .target( name: "Chat", - dependencies: ["WalletConnectRelay", "WalletConnectUtils", "WalletConnectKMS"], + dependencies: ["WalletConnectNetworking"], path: "Sources/Chat"), .target( name: "Auth", - dependencies: [ - "WalletConnectPairing", - "WalletConnectNetworking", - .product(name: "Web3", package: "Web3.swift") - ], + dependencies: ["WalletConnectPairing", "WalletConnectNetworking", .product(name: "Web3", package: "Web3.swift")], path: "Sources/Auth"), .target( name: "WalletConnectRelay", @@ -68,12 +64,7 @@ let package = Package( dependencies: []), .target( name: "WalletConnectNetworking", - dependencies: [ - "JSONRPC", - "WalletConnectKMS", - "WalletConnectRelay", - "WalletConnectUtils", - ]), + dependencies: ["JSONRPC", "WalletConnectKMS", "WalletConnectRelay", "WalletConnectUtils"]), .target( name: "WalletConnectRouter", dependencies: []), @@ -94,7 +85,7 @@ let package = Package( dependencies: ["WalletConnectKMS", "WalletConnectUtils", "TestingUtils"]), .target( name: "TestingUtils", - dependencies: ["WalletConnectUtils", "WalletConnectKMS", "JSONRPC", "WalletConnectPairing"], + dependencies: ["WalletConnectPairing", "WalletConnectNetworking"], path: "Tests/TestingUtils"), .testTarget( name: "WalletConnectUtilsTests", diff --git a/Sources/Auth/AuthClientFactory.swift b/Sources/Auth/AuthClientFactory.swift index b084a1846..469fa37a6 100644 --- a/Sources/Auth/AuthClientFactory.swift +++ b/Sources/Auth/AuthClientFactory.swift @@ -42,6 +42,7 @@ public struct AuthClientFactory { pendingRequestsProvider: pendingRequestsProvider, cleanupService: cleanupService, logger: logger, - pairingStorage: pairingStore, socketConnectionStatusPublisher: relayClient.socketConnectionStatusPublisher) + pairingStorage: pairingStore, + socketConnectionStatusPublisher: relayClient.socketConnectionStatusPublisher) } } diff --git a/Sources/Chat/ChatClient.swift b/Sources/Chat/ChatClient.swift index 1c44bbeb6..678a3436e 100644 --- a/Sources/Chat/ChatClient.swift +++ b/Sources/Chat/ChatClient.swift @@ -2,6 +2,7 @@ import Foundation import WalletConnectUtils import WalletConnectKMS import WalletConnectRelay +import WalletConnectNetworking import Combine public class ChatClient { @@ -16,7 +17,7 @@ public class ChatClient { private let kms: KeyManagementService private let threadStore: Database private let messagesStore: Database - private let invitePayloadStore: CodableStore<(RequestSubscriptionPayload)> + private let invitePayloadStore: CodableStore public let socketConnectionStatusPublisher: AnyPublisher @@ -47,7 +48,7 @@ public class ChatClient { kms: KeyManagementService, threadStore: Database, messagesStore: Database, - invitePayloadStore: CodableStore<(RequestSubscriptionPayload)>, + invitePayloadStore: CodableStore, socketConnectionStatusPublisher: AnyPublisher ) { self.registry = registry @@ -121,7 +122,7 @@ public class ChatClient { public func getInvites(account: Account) -> [Invite] { var invites = [Invite]() invitePayloadStore.getAll().forEach { - guard case .invite(let invite) = $0.request.params else {return} + guard let invite = try? $0.request.params?.get(Invite.self) else {return} invites.append(invite) } return invites diff --git a/Sources/Chat/ChatClientFactory.swift b/Sources/Chat/ChatClientFactory.swift index 89f4907b1..47ae2dcdd 100644 --- a/Sources/Chat/ChatClientFactory.swift +++ b/Sources/Chat/ChatClientFactory.swift @@ -2,6 +2,7 @@ import Foundation import WalletConnectRelay import WalletConnectUtils import WalletConnectKMS +import WalletConnectNetworking public struct ChatClientFactory { @@ -10,17 +11,18 @@ public struct ChatClientFactory { relayClient: RelayClient, kms: KeyManagementService, logger: ConsoleLogging, - keyValueStorage: KeyValueStorage) -> ChatClient { + keyValueStorage: KeyValueStorage + ) -> ChatClient { let topicToRegistryRecordStore = CodableStore(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.topicToInvitationPubKey.rawValue) let serialiser = Serializer(kms: kms) - let jsonRpcHistory = JsonRpcHistory(logger: logger, keyValueStore: CodableStore(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.jsonRpcHistory.rawValue)) - let networkingInteractor = NetworkingInteractor(relayClient: relayClient, serializer: serialiser, logger: logger, jsonRpcHistory: jsonRpcHistory) + let rpcHistory = RPCHistory(keyValueStore: CodableStore(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.jsonRpcHistory.rawValue)) + let networkingInteractor = NetworkingInteractor(relayClient: relayClient, serializer: serialiser, logger: logger, rpcHistory: rpcHistory) let invitePayloadStore = CodableStore(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.invite.rawValue) let registryService = RegistryService(registry: registry, networkingInteractor: networkingInteractor, kms: kms, logger: logger, topicToRegistryRecordStore: topicToRegistryRecordStore) let threadStore = Database(keyValueStorage: keyValueStorage, identifier: StorageDomainIdentifiers.threads.rawValue) let resubscriptionService = ResubscriptionService(networkingInteractor: networkingInteractor, threadStore: threadStore, logger: logger) let invitationHandlingService = InvitationHandlingService(registry: registry, networkingInteractor: networkingInteractor, kms: kms, logger: logger, topicToRegistryRecordStore: topicToRegistryRecordStore, invitePayloadStore: invitePayloadStore, threadsStore: threadStore) - let inviteService = InviteService(networkingInteractor: networkingInteractor, kms: kms, threadStore: threadStore, logger: logger) + let inviteService = InviteService(networkingInteractor: networkingInteractor, kms: kms, threadStore: threadStore, rpcHistory: rpcHistory, logger: logger) let leaveService = LeaveService() let messagesStore = Database(keyValueStorage: keyValueStorage, identifier: StorageDomainIdentifiers.messages.rawValue) let messagingService = MessagingService(networkingInteractor: networkingInteractor, messagesStore: messagesStore, threadStore: threadStore, logger: logger) diff --git a/Sources/Chat/NetworkingInteractor.swift b/Sources/Chat/NetworkingInteractor.swift deleted file mode 100644 index ee31ec033..000000000 --- a/Sources/Chat/NetworkingInteractor.swift +++ /dev/null @@ -1,122 +0,0 @@ -import Foundation -import Combine -import WalletConnectRelay -import WalletConnectUtils -import WalletConnectKMS - -protocol NetworkInteracting { - var socketConnectionStatusPublisher: AnyPublisher { get } - var requestPublisher: AnyPublisher {get} - var responsePublisher: AnyPublisher {get} - func respondSuccess(payload: RequestSubscriptionPayload) async throws - func subscribe(topic: String) async throws - func request(_ request: JSONRPCRequest, topic: String, envelopeType: Envelope.EnvelopeType) async throws - func respond(topic: String, response: JsonRpcResult, tag: Int) async throws -} - -extension NetworkInteracting { - func request(_ request: JSONRPCRequest, topic: String, envelopeType: Envelope.EnvelopeType = .type0) async throws { - try await self.request(request, topic: topic, envelopeType: envelopeType) - } -} - -class NetworkingInteractor: NetworkInteracting { - enum Error: Swift.Error { - case failedToInitialiseMethodFromRecord - } - private let jsonRpcHistory: JsonRpcHistory - private let serializer: Serializing - private let relayClient: RelayClient - private let logger: ConsoleLogging - var requestPublisher: AnyPublisher { - requestPublisherSubject.eraseToAnyPublisher() - } - private let requestPublisherSubject = PassthroughSubject() - - var responsePublisher: AnyPublisher { - responsePublisherSubject.eraseToAnyPublisher() - } - private let responsePublisherSubject = PassthroughSubject() - var socketConnectionStatusPublisher: AnyPublisher - - private var publishers = Set() - - init(relayClient: RelayClient, - serializer: Serializing, - logger: ConsoleLogging, - jsonRpcHistory: JsonRpcHistory - ) { - self.relayClient = relayClient - self.serializer = serializer - self.jsonRpcHistory = jsonRpcHistory - self.logger = logger - self.socketConnectionStatusPublisher = relayClient.socketConnectionStatusPublisher - - relayClient.messagePublisher.sink { [unowned self] (topic, message) in - manageSubscription(topic, message) - }.store(in: &publishers) - } - - func request(_ request: JSONRPCRequest, topic: String, envelopeType: Envelope.EnvelopeType) async throws { - try jsonRpcHistory.set(topic: topic, request: request) - let message = try! serializer.serialize(topic: topic, encodable: request, envelopeType: envelopeType) - try await relayClient.publish(topic: topic, payload: message, tag: request.params.tag) - } - - func respondSuccess(payload: RequestSubscriptionPayload) async throws { - let response = JSONRPCResponse(id: payload.request.id, result: AnyCodable(true)) - try await respond(topic: payload.topic, response: JsonRpcResult.response(response), tag: payload.request.params.responseTag) - } - - func respond(topic: String, response: JsonRpcResult, tag: Int) async throws { - _ = try jsonRpcHistory.resolve(response: response) - let message = try serializer.serialize(topic: topic, encodable: response.value) - try await relayClient.publish(topic: topic, payload: message, tag: tag, prompt: false) - } - - func subscribe(topic: String) async throws { - try await relayClient.subscribe(topic: topic) - } - - private func manageSubscription(_ topic: String, _ encodedEnvelope: String) { - if let deserializedJsonRpcRequest: JSONRPCRequest = serializer.tryDeserialize(topic: topic, encodedEnvelope: encodedEnvelope) { - handleChatRequest(topic: topic, request: deserializedJsonRpcRequest) - } else if let deserializedJsonRpcResponse: JSONRPCResponse = serializer.tryDeserialize(topic: topic, encodedEnvelope: encodedEnvelope) { - handleJsonRpcResponse(response: deserializedJsonRpcResponse) - } else if let deserializedJsonRpcError: JSONRPCErrorResponse = serializer.tryDeserialize(topic: topic, encodedEnvelope: encodedEnvelope) { - handleJsonRpcErrorResponse(response: deserializedJsonRpcError) - } else { - logger.warn("Networking Interactor - Received unknown object type from networking relay") - } - } - - private func handleChatRequest(topic: String, request: JSONRPCRequest) { - do { - try jsonRpcHistory.set(topic: topic, request: request) - let payload = RequestSubscriptionPayload(topic: topic, request: request) - requestPublisherSubject.send(payload) - } catch { - logger.debug(error) - } - } - - private func handleJsonRpcResponse(response: JSONRPCResponse) { - do { - let record = try jsonRpcHistory.resolve(response: JsonRpcResult.response(response)) - let params = try record.request.params.get(ChatRequestParams.self) - let chatResponse = ChatResponse( - topic: record.topic, - requestMethod: record.request.method, - requestParams: params, - result: JsonRpcResult.response(response)) - responsePublisherSubject.send(chatResponse) - } catch { - logger.debug("Handle json rpc response error: \(error)") - } - } - - private func handleJsonRpcErrorResponse(response: JSONRPCErrorResponse) { - // todo - } - -} diff --git a/Sources/Chat/ProtocolServices/Common/File.swift b/Sources/Chat/ProtocolServices/Common/File.swift index 8bd04f569..e821f03d7 100644 --- a/Sources/Chat/ProtocolServices/Common/File.swift +++ b/Sources/Chat/ProtocolServices/Common/File.swift @@ -1,6 +1,8 @@ import Foundation -import WalletConnectUtils import Combine +import WalletConnectRelay +import WalletConnectUtils +import WalletConnectNetworking class ResubscriptionService { private let networkingInteractor: NetworkInteracting diff --git a/Sources/Chat/ProtocolServices/Common/MessagingService.swift b/Sources/Chat/ProtocolServices/Common/MessagingService.swift index ca774136d..eaeaf061e 100644 --- a/Sources/Chat/ProtocolServices/Common/MessagingService.swift +++ b/Sources/Chat/ProtocolServices/Common/MessagingService.swift @@ -1,6 +1,8 @@ import Foundation -import WalletConnectUtils import Combine +import JSONRPC +import WalletConnectUtils +import WalletConnectNetworking class MessagingService { enum Errors: Error { @@ -31,8 +33,8 @@ class MessagingService { guard let authorAccount = thread?.selfAccount else { throw Errors.threadDoNotExist} let timestamp = Int64(Date().timeIntervalSince1970 * 1000) let message = Message(topic: topic, message: messageString, authorAccount: authorAccount, timestamp: timestamp) - let request = JSONRPCRequest(params: .message(message)) - try await networkingInteractor.request(request, topic: topic, envelopeType: .type0) + let request = RPCRequest(method: Message.method, params: message) + try await networkingInteractor.request(request, topic: topic, tag: Message.tag) Task(priority: .background) { await messagesStore.add(message) onMessage?(message) @@ -41,38 +43,34 @@ class MessagingService { private func setUpResponseHandling() { networkingInteractor.responsePublisher - .sink { [unowned self] response in - switch response.requestParams { - case .message: - handleMessageResponse(response) - default: - return - } + .sink { [unowned self] payload in + logger.debug("Received Message response") }.store(in: &publishers) } private func setUpRequestHandling() { - networkingInteractor.requestPublisher.sink { [unowned self] subscriptionPayload in - switch subscriptionPayload.request.params { - case .message(var message): - message.topic = subscriptionPayload.topic - handleMessage(message, subscriptionPayload) - default: - return + networkingInteractor.requestPublisher.sink { [unowned self] payload in + do { + guard + let requestId = payload.request.id, payload.request.method == Message.method, + var message = try payload.request.params?.get(Message.self) + else { return } + + message.topic = payload.topic + + handleMessage(message, topic: payload.topic, requestId: requestId) + } catch { + logger.debug("Handling message response has failed") } }.store(in: &publishers) } - private func handleMessage(_ message: Message, _ payload: RequestSubscriptionPayload) { + private func handleMessage(_ message: Message, topic: String, requestId: RPCID) { Task(priority: .background) { - try await networkingInteractor.respondSuccess(payload: payload) + try await networkingInteractor.respondSuccess(topic: topic, requestId: requestId, tag: Message.tag) await messagesStore.add(message) logger.debug("Received message") onMessage?(message) } } - - private func handleMessageResponse(_ response: ChatResponse) { - logger.debug("Received Message response") - } } diff --git a/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift b/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift index 38021014b..102e9f00a 100644 --- a/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift +++ b/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift @@ -1,8 +1,10 @@ import Foundation +import Combine +import JSONRPC import WalletConnectKMS import WalletConnectUtils import WalletConnectRelay -import Combine +import WalletConnectNetworking class InvitationHandlingService { enum Error: Swift.Error { @@ -11,7 +13,7 @@ class InvitationHandlingService { var onInvite: ((Invite) -> Void)? var onNewThread: ((Thread) -> Void)? private let networkingInteractor: NetworkInteracting - private let invitePayloadStore: CodableStore<(RequestSubscriptionPayload)> + private let invitePayloadStore: CodableStore private let topicToRegistryRecordStore: CodableStore private let registry: Registry private let logger: ConsoleLogging @@ -37,27 +39,22 @@ class InvitationHandlingService { } func accept(inviteId: String) async throws { - guard let payload = try invitePayloadStore.get(key: inviteId) else { throw Error.inviteForIdNotFound } let selfThreadPubKey = try kms.createX25519KeyPair() let inviteResponse = InviteResponse(publicKey: selfThreadPubKey.hexRepresentation) - let response = JsonRpcResult.response(JSONRPCResponse(id: payload.request.id, result: AnyCodable(inviteResponse))) - - guard case .invite(let invite) = payload.request.params else {return} + guard let requestId = payload.request.id, let invite = try? payload.request.params?.get(Invite.self) + else { return } - let responseTopic = try getInviteResponseTopic(payload, invite) - - try await networkingInteractor.respond(topic: responseTopic, response: response, tag: payload.request.params.responseTag) + let response = RPCResponse(id: requestId, result: inviteResponse) + let responseTopic = try getInviteResponseTopic(requestTopic: payload.topic, invite: invite) + try await networkingInteractor.respond(topic: responseTopic, response: response, tag: Invite.tag) let threadAgreementKeys = try kms.performKeyAgreement(selfPublicKey: selfThreadPubKey, peerPublicKey: invite.publicKey) - let threadTopic = threadAgreementKeys.derivedTopic() - try kms.setSymmetricKey(threadAgreementKeys.sharedKey, for: threadTopic) - try await networkingInteractor.subscribe(topic: threadTopic) logger.debug("Accepting an invite on topic: \(threadTopic)") @@ -73,47 +70,36 @@ class InvitationHandlingService { } func reject(inviteId: String) async throws { - guard let payload = try invitePayloadStore.get(key: inviteId) else { throw Error.inviteForIdNotFound } - guard case .invite(let invite) = payload.request.params else {return} + guard let requestId = payload.request.id, let invite = try? payload.request.params?.get(Invite.self) + else { return } - let responseTopic = try getInviteResponseTopic(payload, invite) + let responseTopic = try getInviteResponseTopic(requestTopic: payload.topic, invite: invite) - // TODO - error not in specs yet - let error = JSONRPCErrorResponse.Error(code: 0, message: "user rejected") - let response = JsonRpcResult.error(JSONRPCErrorResponse(id: payload.request.id, error: error)) - - try await networkingInteractor.respond(topic: responseTopic, response: response, tag: payload.request.params.responseTag) + try await networkingInteractor.respondError(topic: responseTopic, requestId: requestId, tag: Invite.tag, reason: ChatError.userRejected) invitePayloadStore.delete(forKey: inviteId) } private func setUpRequestHandling() { - networkingInteractor.requestPublisher.sink { [unowned self] subscriptionPayload in - switch subscriptionPayload.request.params { - case .invite(let invite): - do { - try handleInvite(invite, subscriptionPayload) - } catch { - logger.debug("Did not handle invite, error: \(error)") - } - default: - return - } - }.store(in: &publishers) - } + networkingInteractor.requestPublisher.sink { [unowned self] payload in + guard payload.request.method == "wc_chatInvite" + else { return } + + guard let invite = try? payload.request.params?.get(Invite.self) + else { return } - private func handleInvite(_ invite: Invite, _ payload: RequestSubscriptionPayload) throws { - logger.debug("did receive an invite") - invitePayloadStore.set(payload, forKey: invite.publicKey) - onInvite?(invite) + logger.debug("did receive an invite") + invitePayloadStore.set(payload, forKey: invite.publicKey) + onInvite?(invite) + }.store(in: &publishers) } - private func getInviteResponseTopic(_ payload: RequestSubscriptionPayload, _ invite: Invite) throws -> String { + private func getInviteResponseTopic(requestTopic: String, invite: Invite) throws -> String { // todo - remove topicToInvitationPubKeyStore ? - guard let record = try? topicToRegistryRecordStore.get(key: payload.topic) else { + guard let record = try? topicToRegistryRecordStore.get(key: requestTopic) else { logger.debug("PubKey for invitation topic not found") fatalError("todo") } diff --git a/Sources/Chat/ProtocolServices/Invitee/RegistryService.swift b/Sources/Chat/ProtocolServices/Invitee/RegistryService.swift index 33a5241a8..4476f306e 100644 --- a/Sources/Chat/ProtocolServices/Invitee/RegistryService.swift +++ b/Sources/Chat/ProtocolServices/Invitee/RegistryService.swift @@ -1,6 +1,7 @@ import Foundation import WalletConnectUtils import WalletConnectKMS +import WalletConnectNetworking actor RegistryService { let networkingInteractor: NetworkInteracting diff --git a/Sources/Chat/ProtocolServices/Inviter/InviteService.swift b/Sources/Chat/ProtocolServices/Inviter/InviteService.swift index f3a5d32b9..d3051cf2d 100644 --- a/Sources/Chat/ProtocolServices/Inviter/InviteService.swift +++ b/Sources/Chat/ProtocolServices/Inviter/InviteService.swift @@ -1,7 +1,9 @@ import Foundation +import Combine +import JSONRPC import WalletConnectKMS import WalletConnectUtils -import Combine +import WalletConnectNetworking class InviteService { private var publishers = [AnyCancellable]() @@ -9,6 +11,7 @@ class InviteService { private let logger: ConsoleLogging private let kms: KeyManagementService private let threadStore: Database + private let rpcHistory: RPCHistory var onNewThread: ((Thread) -> Void)? var onInvite: ((Invite) -> Void)? @@ -16,11 +19,13 @@ class InviteService { init(networkingInteractor: NetworkInteracting, kms: KeyManagementService, threadStore: Database, + rpcHistory: RPCHistory, logger: ConsoleLogging) { self.kms = kms self.networkingInteractor = networkingInteractor self.logger = logger self.threadStore = threadStore + self.rpcHistory = rpcHistory setUpResponseHandling() } @@ -37,7 +42,7 @@ class InviteService { // overrides on invite toipic try kms.setSymmetricKey(symKeyI.sharedKey, for: inviteTopic) - let request = JSONRPCRequest(params: .invite(invite)) + let request = RPCRequest(method: Invite.method, params: invite) // 2. Proposer subscribes to topic R which is the hash of the derived symKey let responseTopic = symKeyI.derivedTopic() @@ -45,40 +50,35 @@ class InviteService { try kms.setSymmetricKey(symKeyI.sharedKey, for: responseTopic) try await networkingInteractor.subscribe(topic: responseTopic) - try await networkingInteractor.request(request, topic: inviteTopic, envelopeType: .type1(pubKey: selfPubKeyY.rawRepresentation)) + try await networkingInteractor.request(request, topic: inviteTopic, tag: Invite.tag, envelopeType: .type1(pubKey: selfPubKeyY.rawRepresentation)) logger.debug("invite sent on topic: \(inviteTopic)") } private func setUpResponseHandling() { networkingInteractor.responsePublisher - .sink { [unowned self] response in - switch response.requestParams { - case .invite: - handleInviteResponse(response) - default: - return - } - }.store(in: &publishers) - } + .sink { [unowned self] payload in + do { + guard + let requestId = payload.response.id, + let request = rpcHistory.get(recordId: requestId)?.request, + let requestParams = request.params, request.method == Invite.method + else { return } - private func handleInviteResponse(_ response: ChatResponse) { - switch response.result { - case .response(let jsonrpc): - do { - let inviteResponse = try jsonrpc.result.get(InviteResponse.self) - logger.debug("Invite has been accepted") - guard case .invite(let inviteParams) = response.requestParams else { return } - Task(priority: .background) { - try await createThread(selfPubKeyHex: inviteParams.publicKey, peerPubKey: inviteResponse.publicKey, account: inviteParams.account, peerAccount: peerAccount) + guard let inviteResponse = try payload.response.result?.get(InviteResponse.self) + else { return } + + let inviteParams = try requestParams.get(Invite.self) + + logger.debug("Invite has been accepted") + + Task(priority: .background) { + try await createThread(selfPubKeyHex: inviteParams.publicKey, peerPubKey: inviteResponse.publicKey, account: inviteParams.account, peerAccount: peerAccount) + } + } catch { + logger.debug("Handling invite response has failed") } - } catch { - logger.debug("Handling invite response has failed") - } - case .error: - logger.debug("Invite has been rejected") - // TODO - remove keys, clean storage - } + }.store(in: &publishers) } private func createThread(selfPubKeyHex: String, peerPubKey: String, account: Account, peerAccount: Account) async throws { diff --git a/Sources/Chat/Types/ChatError.swift b/Sources/Chat/Types/ChatError.swift index 0672ba16f..edac89e77 100644 --- a/Sources/Chat/Types/ChatError.swift +++ b/Sources/Chat/Types/ChatError.swift @@ -1,6 +1,21 @@ import Foundation +import WalletConnectNetworking enum ChatError: Error { case noInviteForId case recordNotFound + case userRejected +} + +extension ChatError: Reason { + + var code: Int { + // Errors not in specs yet + return 0 + } + + var message: String { + // Errors not in specs yet + return localizedDescription + } } diff --git a/Sources/Chat/Types/ChatRequestParams.swift b/Sources/Chat/Types/ChatRequestParams.swift deleted file mode 100644 index 51b9e512d..000000000 --- a/Sources/Chat/Types/ChatRequestParams.swift +++ /dev/null @@ -1,63 +0,0 @@ -import Foundation -import WalletConnectUtils - -enum ChatRequestParams: Codable, Equatable { - enum Errors: Error { - case decoding - } - case invite(Invite) - case message(Message) - - private enum CodingKeys: String, CodingKey { - case invite - case message - } - - func encode(to encoder: Encoder) throws { - switch self { - case .invite(let invite): - try invite.encode(to: encoder) - case .message(let message): - try message.encode(to: encoder) - } - } - - init(from decoder: Decoder) throws { - if let invite = try? Invite(from: decoder) { - self = .invite(invite) - } else if let massage = try? Message(from: decoder) { - self = .message(massage) - } else { - throw Errors.decoding - } - } -} - -extension ChatRequestParams { - - var tag: Int { - switch self { - case .invite: - return 2000 - case .message: - return 2002 - } - } - - var responseTag: Int { - return tag + 1 - } -} - -extension JSONRPCRequest { - init(id: Int64 = JsonRpcID.generate(), params: T) where T == ChatRequestParams { - var method: String! - switch params { - case .invite: - method = "wc_chatInvite" - case .message: - method = "wc_chatMessage" - } - self.init(id: id, method: method, params: params) - } -} diff --git a/Sources/Chat/Types/ChatResponse.swift b/Sources/Chat/Types/ChatResponse.swift deleted file mode 100644 index 448abb7e8..000000000 --- a/Sources/Chat/Types/ChatResponse.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation -import WalletConnectUtils - -struct ChatResponse: Codable { - let topic: String - let requestMethod: String - let requestParams: ChatRequestParams - let result: JsonRpcResult -} diff --git a/Sources/Chat/Types/InviteParams.swift b/Sources/Chat/Types/Invite.swift similarity index 71% rename from Sources/Chat/Types/InviteParams.swift rename to Sources/Chat/Types/Invite.swift index f5b0f7180..5f69e72e8 100644 --- a/Sources/Chat/Types/InviteParams.swift +++ b/Sources/Chat/Types/Invite.swift @@ -12,4 +12,12 @@ public struct Invite: Codable, Equatable { public let message: String public let account: Account public let publicKey: String + + static var tag: Int { + return 2000 + } + + static var method: String { + return "wc_chatInvite" + } } diff --git a/Sources/Chat/Types/Message.swift b/Sources/Chat/Types/Message.swift index 7325d8a21..09113ed2a 100644 --- a/Sources/Chat/Types/Message.swift +++ b/Sources/Chat/Types/Message.swift @@ -2,13 +2,6 @@ import Foundation import WalletConnectUtils public struct Message: Codable, Equatable { - internal init(topic: String? = nil, message: String, authorAccount: Account, timestamp: Int64) { - self.topic = topic - self.message = message - self.authorAccount = authorAccount - self.timestamp = timestamp - } - public var topic: String? public let message: String public let authorAccount: Account @@ -20,4 +13,19 @@ public struct Message: Codable, Equatable { case authorAccount case timestamp } + + static var tag: Int { + return 2002 + } + + static var method: String { + return "wc_chatMessage" + } + + init(topic: String? = nil, message: String, authorAccount: Account, timestamp: Int64) { + self.topic = topic + self.message = message + self.authorAccount = authorAccount + self.timestamp = timestamp + } } diff --git a/Sources/Chat/Types/RequestSubscriptionPayload.swift b/Sources/Chat/Types/RequestSubscriptionPayload.swift deleted file mode 100644 index 575af574a..000000000 --- a/Sources/Chat/Types/RequestSubscriptionPayload.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation -import WalletConnectUtils - -struct RequestSubscriptionPayload: Codable { - let topic: String - let request: JSONRPCRequest -} diff --git a/Sources/WalletConnectNetworking/NetworkInteractor.swift b/Sources/WalletConnectNetworking/NetworkInteractor.swift index 668448236..fca33ed16 100644 --- a/Sources/WalletConnectNetworking/NetworkInteractor.swift +++ b/Sources/WalletConnectNetworking/NetworkInteractor.swift @@ -2,20 +2,35 @@ import Foundation import Combine import JSONRPC import WalletConnectKMS +import WalletConnectRelay public protocol NetworkInteracting { - var requestPublisher: AnyPublisher {get} - var responsePublisher: AnyPublisher {get} + var socketConnectionStatusPublisher: AnyPublisher { get } + var requestPublisher: AnyPublisher { get } + var responsePublisher: AnyPublisher { get } func subscribe(topic: String) async throws func unsubscribe(topic: String) func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws + func respondSuccess(topic: String, requestId: RPCID, tag: Int, envelopeType: Envelope.EnvelopeType) async throws func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws } extension NetworkInteracting { - public func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType = .type0) async throws { - try await self.request(request, topic: topic, tag: tag, envelopeType: envelopeType) + public func request(_ request: RPCRequest, topic: String, tag: Int) async throws { + try await self.request(request, topic: topic, tag: tag, envelopeType: .type0) + } + + public func respond(topic: String, response: RPCResponse, tag: Int) async throws { + try await self.respond(topic: topic, response: response, tag: tag, envelopeType: .type0) + } + + public func respondSuccess(topic: String, requestId: RPCID, tag: Int) async throws { + try await self.respondSuccess(topic: topic, requestId: requestId, tag: tag, envelopeType: .type0) + } + + public func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason) async throws { + try await self.respondError(topic: topic, requestId: requestId, tag: tag, reason: reason, envelopeType: .type0) } } diff --git a/Sources/WalletConnectNetworking/NetworkingInteractor.swift b/Sources/WalletConnectNetworking/NetworkingInteractor.swift index 91a664578..cf4f99e46 100644 --- a/Sources/WalletConnectNetworking/NetworkingInteractor.swift +++ b/Sources/WalletConnectNetworking/NetworkingInteractor.swift @@ -27,9 +27,9 @@ public class NetworkingInteractor: NetworkInteracting { public init( relayClient: RelayClient, - serializer: Serializing, - logger: ConsoleLogging, - rpcHistory: RPCHistory + serializer: Serializing, + logger: ConsoleLogging, + rpcHistory: RPCHistory ) { self.relayClient = relayClient self.serializer = serializer @@ -89,11 +89,15 @@ public class NetworkingInteractor: NetworkInteracting { try await relayClient.publish(topic: topic, payload: message, tag: tag) } + public func respondSuccess(topic: String, requestId: RPCID, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { + let response = RPCResponse(id: requestId, result: true) + try await respond(topic: topic, response: response, tag: tag, envelopeType: envelopeType) + } + public func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws { let error = JSONRPCError(code: reason.code, message: reason.message) let response = RPCResponse(id: requestId, error: error) - let message = try! serializer.serialize(topic: topic, encodable: response, envelopeType: envelopeType) - try await relayClient.publish(topic: topic, payload: message, tag: tag) + try await respond(topic: topic, response: response, tag: tag, envelopeType: envelopeType) } private func manageSubscription(_ topic: String, _ encodedEnvelope: String) { diff --git a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift b/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift deleted file mode 100644 index 5c9664d03..000000000 --- a/Tests/AuthTests/Mocks/NetworkingInteractorMock.swift +++ /dev/null @@ -1,44 +0,0 @@ -import Foundation -import Combine -@testable import Auth -import JSONRPC -import WalletConnectKMS -import WalletConnectNetworking - -struct NetworkingInteractorMock: NetworkInteracting { - - var responsePublisher: AnyPublisher { - responsePublisherSubject.eraseToAnyPublisher() - } - let responsePublisherSubject = PassthroughSubject() - - let requestPublisherSubject = PassthroughSubject() - var requestPublisher: AnyPublisher { - requestPublisherSubject.eraseToAnyPublisher() - } - - func subscribe(topic: String) async throws { - - } - - func unsubscribe(topic: String) { - - } - - func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { - - } - - func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { - - } - - func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws { - - } - - func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws { - - } - -} diff --git a/Tests/ChatTests/Mocks/NetworkingInteractorMock.swift b/Tests/ChatTests/Mocks/NetworkingInteractorMock.swift deleted file mode 100644 index 030c9d1d9..000000000 --- a/Tests/ChatTests/Mocks/NetworkingInteractorMock.swift +++ /dev/null @@ -1,50 +0,0 @@ -import Foundation -@testable import Chat -import Combine -import WalletConnectUtils -import WalletConnectRelay - -class NetworkingInteractorMock: NetworkInteracting { - - var socketConnectionStatusPublisher: AnyPublisher { - socketConnectionStatusPublisherSubject.eraseToAnyPublisher() - } - let socketConnectionStatusPublisherSubject = PassthroughSubject() - - let responsePublisherSubject = PassthroughSubject() - let requestPublisherSubject = PassthroughSubject() - - var requestPublisher: AnyPublisher { - requestPublisherSubject.eraseToAnyPublisher() - } - - var responsePublisher: AnyPublisher { - responsePublisherSubject.eraseToAnyPublisher() - } - - func requestUnencrypted(_ request: JSONRPCRequest, topic: String) async throws { - - } - - func request(_ request: JSONRPCRequest, topic: String) async throws { - - } - - func respond(topic: String, response: JsonRpcResult, tag: Int) async throws { - - } - - func respondSuccess(payload: RequestSubscriptionPayload) async throws { - - } - - private(set) var subscriptions: [String] = [] - - func subscribe(topic: String) async throws { - subscriptions.append(topic) - } - - func didSubscribe(to topic: String) -> Bool { - subscriptions.contains { $0 == topic } - } -} diff --git a/Tests/ChatTests/RegistryManagerTests.swift b/Tests/ChatTests/RegistryManagerTests.swift index b0ea58338..c9ff87848 100644 --- a/Tests/ChatTests/RegistryManagerTests.swift +++ b/Tests/ChatTests/RegistryManagerTests.swift @@ -2,7 +2,8 @@ import Foundation import XCTest @testable import Chat import WalletConnectUtils -@testable import WalletConnectKMS +import WalletConnectNetworking +import WalletConnectKMS @testable import TestingUtils final class RegistryManagerTests: XCTestCase { @@ -27,7 +28,7 @@ final class RegistryManagerTests: XCTestCase { func testRegister() async { let account = Account("eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb")! - try! await registryManager.register(account: account) + _ = try! await registryManager.register(account: account) XCTAssert(!networkingInteractor.subscriptions.isEmpty, "networkingInteractors subscribes to new topic") let resolved = try! await registry.resolve(account: account) XCTAssertNotNil(resolved, "register account is resolvable") diff --git a/Tests/TestingUtils/NetworkingInteractorMock.swift b/Tests/TestingUtils/NetworkingInteractorMock.swift new file mode 100644 index 000000000..70abbc425 --- /dev/null +++ b/Tests/TestingUtils/NetworkingInteractorMock.swift @@ -0,0 +1,58 @@ +import Foundation +import Combine +import JSONRPC +import WalletConnectRelay +import WalletConnectKMS +import WalletConnectNetworking + +public class NetworkingInteractorMock: NetworkInteracting { + + private(set) var subscriptions: [String] = [] + + public let socketConnectionStatusPublisherSubject = PassthroughSubject() + public var socketConnectionStatusPublisher: AnyPublisher { + socketConnectionStatusPublisherSubject.eraseToAnyPublisher() + } + + public var responsePublisher: AnyPublisher { + responsePublisherSubject.eraseToAnyPublisher() + } + public let responsePublisherSubject = PassthroughSubject() + + public let requestPublisherSubject = PassthroughSubject() + public var requestPublisher: AnyPublisher { + requestPublisherSubject.eraseToAnyPublisher() + } + + public func subscribe(topic: String) async throws { + subscriptions.append(topic) + } + + func didSubscribe(to topic: String) -> Bool { + subscriptions.contains { $0 == topic } + } + + public func unsubscribe(topic: String) { + + } + + public func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { + + } + + public func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { + + } + + public func respondSuccess(topic: String, requestId: RPCID, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { + + } + + public func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws { + + } + + public func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws { + + } +} From 429b32e478a570518738df422c6a6d3914248c0d Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Thu, 1 Sep 2022 22:26:55 +0300 Subject: [PATCH 04/13] Showcase build errors --- .../Showcase/Classes/ApplicationLayer/SceneDelegate.swift | 2 +- .../PresentationLayer/Wallet/Wallet/WalletInteractor.swift | 2 +- .../PresentationLayer/Wallet/Wallet/WalletPresenter.swift | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift b/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift index 43335bd7d..5956c494e 100644 --- a/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift +++ b/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift @@ -30,7 +30,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let uri = context.url.absoluteString.replacingOccurrences(of: "showcase://wc?uri=", with: "") Task { - try await Auth.instance.pair(uri: uri) + try await Auth.instance.pair(uri: WalletConnectURI(string: uri)!) } } } diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift index ac53b05f3..051ba266e 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift +++ b/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift @@ -3,7 +3,7 @@ import Auth final class WalletInteractor { - func pair(uri: String) async throws { + func pair(uri: WalletConnectURI) async throws { try await Auth.instance.pair(uri: uri) } diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift index 2f631ad65..47a773591 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift @@ -15,13 +15,14 @@ final class WalletPresenter: ObservableObject { } func didPastePairingURI() { - guard let uri = UIPasteboard.general.string else { return } + guard let string = UIPasteboard.general.string, let uri = WalletConnectURI(string: string) else { return } pair(uri: uri) } func didScanPairingURI() { router.presentScan { [unowned self] value in - self.pair(uri: value) + guard let uri = WalletConnectURI(string: value) else { return } + self.pair(uri: uri) self.router.dismiss() } onError: { error in print(error.localizedDescription) @@ -53,7 +54,7 @@ private extension WalletPresenter { }.store(in: &disposeBag) } - func pair(uri: String) { + func pair(uri: WalletConnectURI) { Task(priority: .high) { [unowned self] in try await self.interactor.pair(uri: uri) } From eaccdad46775f9aa2ee16d2eb600c06461070232 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 2 Sep 2022 10:25:42 +0200 Subject: [PATCH 05/13] savepoint --- Sources/Auth/Services/Common/DisconnectPairService.swift | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Sources/Auth/Services/Common/DisconnectPairService.swift diff --git a/Sources/Auth/Services/Common/DisconnectPairService.swift b/Sources/Auth/Services/Common/DisconnectPairService.swift new file mode 100644 index 000000000..881fa1e3b --- /dev/null +++ b/Sources/Auth/Services/Common/DisconnectPairService.swift @@ -0,0 +1,8 @@ +// + +import Foundation + +class DisconnectPairService { + + +} From a54aafd863c2fc95da03f1874a93db89b6e066cb Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 2 Sep 2022 10:55:52 +0200 Subject: [PATCH 06/13] Add disconnect method --- .../Common/DisconnectPairService.swift | 25 ++++++++++++++++++- Sources/Auth/Types/Errors/AuthError.swift | 5 ++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Sources/Auth/Services/Common/DisconnectPairService.swift b/Sources/Auth/Services/Common/DisconnectPairService.swift index 881fa1e3b..b808caaef 100644 --- a/Sources/Auth/Services/Common/DisconnectPairService.swift +++ b/Sources/Auth/Services/Common/DisconnectPairService.swift @@ -1,8 +1,31 @@ -// import Foundation +import WalletConnectNetworking +import WalletConnectKMS +import WalletConnectUtils +import WalletConnectPairing class DisconnectPairService { + private let networkingInteractor: NetworkInteracting + private let kms: KeyManagementServiceProtocol + private let pairingStorage: WCPairingStorage + private let logger: ConsoleLogging + init(networkingInteractor: NetworkInteracting, + kms: KeyManagementServiceProtocol, + pairingStorage: WCPairingStorage, + logger: ConsoleLogging) { + self.networkingInteractor = networkingInteractor + self.kms = kms + self.pairingStorage = pairingStorage + } + func disconnect(topic: String) async throws { + let reason = AuthError.userDisconnected + logger.debug("Will delete pairing for reason: message: \(reason.message) code: \(reason.code)") + try await networkingInteractor.request(<#T##RPCRequest#>, topic: <#T##String#>, tag: <#T##Int#>, envelopeType: <#T##Envelope.EnvelopeType#>) + pairingStorage.delete(topic: topic) + kms.deleteSymmetricKey(for: topic) + networkingInteractor.unsubscribe(topic: topic) + } } diff --git a/Sources/Auth/Types/Errors/AuthError.swift b/Sources/Auth/Types/Errors/AuthError.swift index f28cab817..a8191beff 100644 --- a/Sources/Auth/Types/Errors/AuthError.swift +++ b/Sources/Auth/Types/Errors/AuthError.swift @@ -3,6 +3,7 @@ import WalletConnectNetworking /// Authentication error public enum AuthError: Codable, Equatable, Error { + case userDisconnected case userRejeted case malformedResponseParams case malformedRequestParams @@ -31,6 +32,8 @@ extension AuthError: Reason { public var code: Int { switch self { + case .userDisconnected: + return 6000 case .userRejeted: return 14001 case .malformedResponseParams: @@ -56,6 +59,8 @@ extension AuthError: Reason { return "Original message compromised" case .signatureVerificationFailed: return "Message verification failed" + case .userDisconnected: + return "User Disconnected" } } } From 1e35971241f1e8fad408343a5931aba3ab3534cd Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 2 Sep 2022 13:25:27 +0200 Subject: [PATCH 07/13] savepoint --- Example/ExampleApp.xcodeproj/project.pbxproj | 2 + .../Common/DisconnectPairService.swift | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index c6a979651..fd35fb2eb 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -1752,6 +1752,7 @@ DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Showcase/Other/Info.plist; + INFOPLIST_KEY_NSCameraUsageDescription = "Allow the app to scan for QR codes"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; @@ -1781,6 +1782,7 @@ DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Showcase/Other/Info.plist; + INFOPLIST_KEY_NSCameraUsageDescription = "Allow the app to scan for QR codes"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; diff --git a/Sources/Auth/Services/Common/DisconnectPairService.swift b/Sources/Auth/Services/Common/DisconnectPairService.swift index b808caaef..cd21c09ff 100644 --- a/Sources/Auth/Services/Common/DisconnectPairService.swift +++ b/Sources/Auth/Services/Common/DisconnectPairService.swift @@ -1,11 +1,15 @@ import Foundation import WalletConnectNetworking +import JSONRPC import WalletConnectKMS import WalletConnectUtils import WalletConnectPairing class DisconnectPairService { + enum Errors: Error { + case pairingNotFound + } private let networkingInteractor: NetworkInteracting private let kms: KeyManagementServiceProtocol private let pairingStorage: WCPairingStorage @@ -18,14 +22,46 @@ class DisconnectPairService { self.networkingInteractor = networkingInteractor self.kms = kms self.pairingStorage = pairingStorage + self.logger = logger } - func disconnect(topic: String) async throws { + func delete(topic: String) async throws { + guard pairingStorage.hasPairing(forTopic: topic) else { throw Errors.pairingNotFound} let reason = AuthError.userDisconnected logger.debug("Will delete pairing for reason: message: \(reason.message) code: \(reason.code)") - try await networkingInteractor.request(<#T##RPCRequest#>, topic: <#T##String#>, tag: <#T##Int#>, envelopeType: <#T##Envelope.EnvelopeType#>) + let request = RPCRequest(method: AuthProtocolMethods.pairingDelete.rawValue, params: reason) + try await networkingInteractor.request(request, topic: topic, tag: AuthProtocolMethods.pairingDelete.requestTag) pairingStorage.delete(topic: topic) kms.deleteSymmetricKey(for: topic) networkingInteractor.unsubscribe(topic: topic) } } + + +enum AuthProtocolMethods: String { + case authRequest = "wc_authRequest" + case pairingDelete = "wc_pairingDelete" + case pairingPing = "wc_pairingPing" + + var requestTag: Int { + switch self { + case .authRequest: + return 3000 + case .pairingDelete: + return 1000 + case .pairingPing: + return 1002 + } + } + + var responseTag: Int { + switch self { + case .authRequest: + return 3001 + case .pairingDelete: + return 1001 + case .pairingPing: + return 1003 + } + } +} From 26bc699a6c91f880d1f89d2ba14cf32021c6d63f Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 5 Sep 2022 08:39:33 +0200 Subject: [PATCH 08/13] Add disconnect to auth client api --- Sources/Auth/AuthClient.swift | 8 ++++- Sources/Auth/AuthClientFactory.swift | 3 +- Sources/Auth/AuthProtocolMethods.swift | 29 +++++++++++++++++ ...rvice.swift => DeletePairingService.swift} | 31 +------------------ 4 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 Sources/Auth/AuthProtocolMethods.swift rename Sources/Auth/Services/Common/{DisconnectPairService.swift => DeletePairingService.swift} (68%) diff --git a/Sources/Auth/AuthClient.swift b/Sources/Auth/AuthClient.swift index ba84fe74c..41ab8d3ad 100644 --- a/Sources/Auth/AuthClient.swift +++ b/Sources/Auth/AuthClient.swift @@ -46,6 +46,7 @@ public class AuthClient { private var authRequestPublisherSubject = PassthroughSubject() private let appPairService: AppPairService private let appRequestService: AppRequestService + private let deletePairingService: DeletePairingService private let appRespondSubscriber: AppRespondSubscriber private let walletPairService: WalletPairService private let walletRequestSubscriber: WalletRequestSubscriber @@ -61,6 +62,7 @@ public class AuthClient { walletPairService: WalletPairService, walletRequestSubscriber: WalletRequestSubscriber, walletRespondService: WalletRespondService, + deletePairingService: DeletePairingService, account: Account?, pendingRequestsProvider: PendingRequestsProvider, cleanupService: CleanupService, @@ -80,7 +82,7 @@ public class AuthClient { self.logger = logger self.pairingStorage = pairingStorage self.socketConnectionStatusPublisher = socketConnectionStatusPublisher - + self.deletePairingService = deletePairingService setUpPublishers() } @@ -135,6 +137,10 @@ public class AuthClient { try await walletRespondService.respondError(requestId: requestId) } + public func disconnect(topic: String) async throws { + try await deletePairingService.delete(topic: topic) + } + /// Query pending authentication requests /// - Returns: Pending authentication requests public func getPendingRequests() throws -> [AuthRequest] { diff --git a/Sources/Auth/AuthClientFactory.swift b/Sources/Auth/AuthClientFactory.swift index 469fa37a6..160489b69 100644 --- a/Sources/Auth/AuthClientFactory.swift +++ b/Sources/Auth/AuthClientFactory.swift @@ -31,13 +31,14 @@ public struct AuthClientFactory { let walletRespondService = WalletRespondService(networkingInteractor: networkingInteractor, logger: logger, kms: kms, rpcHistory: history) let pendingRequestsProvider = PendingRequestsProvider(rpcHistory: history) let cleanupService = CleanupService(pairingStore: pairingStore, kms: kms) + let deletePairingService = DeletePairingService(networkingInteractor: networkingInteractor, kms: kms, pairingStorage: pairingStore, logger: logger) return AuthClient(appPairService: appPairService, appRequestService: appRequestService, appRespondSubscriber: appRespondSubscriber, walletPairService: walletPairService, walletRequestSubscriber: walletRequestSubscriber, - walletRespondService: walletRespondService, + walletRespondService: walletRespondService, deletePairingService: deletePairingService, account: account, pendingRequestsProvider: pendingRequestsProvider, cleanupService: cleanupService, diff --git a/Sources/Auth/AuthProtocolMethods.swift b/Sources/Auth/AuthProtocolMethods.swift new file mode 100644 index 000000000..b4ce15058 --- /dev/null +++ b/Sources/Auth/AuthProtocolMethods.swift @@ -0,0 +1,29 @@ +import Foundation + +enum AuthProtocolMethods: String { + case authRequest = "wc_authRequest" + case pairingDelete = "wc_pairingDelete" + case pairingPing = "wc_pairingPing" + + var requestTag: Int { + switch self { + case .authRequest: + return 3000 + case .pairingDelete: + return 1000 + case .pairingPing: + return 1002 + } + } + + var responseTag: Int { + switch self { + case .authRequest: + return 3001 + case .pairingDelete: + return 1001 + case .pairingPing: + return 1003 + } + } +} diff --git a/Sources/Auth/Services/Common/DisconnectPairService.swift b/Sources/Auth/Services/Common/DeletePairingService.swift similarity index 68% rename from Sources/Auth/Services/Common/DisconnectPairService.swift rename to Sources/Auth/Services/Common/DeletePairingService.swift index cd21c09ff..d28546534 100644 --- a/Sources/Auth/Services/Common/DisconnectPairService.swift +++ b/Sources/Auth/Services/Common/DeletePairingService.swift @@ -6,7 +6,7 @@ import WalletConnectKMS import WalletConnectUtils import WalletConnectPairing -class DisconnectPairService { +class DeletePairingService { enum Errors: Error { case pairingNotFound } @@ -36,32 +36,3 @@ class DisconnectPairService { networkingInteractor.unsubscribe(topic: topic) } } - - -enum AuthProtocolMethods: String { - case authRequest = "wc_authRequest" - case pairingDelete = "wc_pairingDelete" - case pairingPing = "wc_pairingPing" - - var requestTag: Int { - switch self { - case .authRequest: - return 3000 - case .pairingDelete: - return 1000 - case .pairingPing: - return 1002 - } - } - - var responseTag: Int { - switch self { - case .authRequest: - return 3001 - case .pairingDelete: - return 1001 - case .pairingPing: - return 1003 - } - } -} From 9d6cfb0fa9b8609432e8b0eff9dc29aa4edc0265 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 5 Sep 2022 09:38:51 +0200 Subject: [PATCH 09/13] add disconnect service for sign --- .../Engine/Common/DeletePairingService.swift | 32 ++++++++++++++++++ .../Engine/Common/DeleteSessionService.swift | 30 +++++++++++++++++ .../Engine/Common/DisconnectService.swift | 33 +++++++++++++++++++ .../Engine/Common/SessionEngine.swift | 9 ----- .../WalletConnectSign/Sign/SignClient.swift | 6 ++-- .../Sign/SignClientFactory.swift | 6 ++-- 6 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift create mode 100644 Sources/WalletConnectSign/Engine/Common/DeleteSessionService.swift create mode 100644 Sources/WalletConnectSign/Engine/Common/DisconnectService.swift diff --git a/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift b/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift new file mode 100644 index 000000000..b2e260b0a --- /dev/null +++ b/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift @@ -0,0 +1,32 @@ +import Foundation +import WalletConnectKMS +import WalletConnectUtils +import WalletConnectPairing + +class DeletePairingService { + private let networkingInteractor: NetworkInteracting + private let kms: KeyManagementServiceProtocol + private let pairingStorage: WCPairingStorage + private let logger: ConsoleLogging + + init(networkingInteractor: NetworkInteracting, + kms: KeyManagementServiceProtocol, + pairingStorage: WCPairingStorage, + logger: ConsoleLogging) { + self.networkingInteractor = networkingInteractor + self.kms = kms + self.pairingStorage = pairingStorage + self.logger = logger + } + + func delete(topic: String) async throws { + let reasonCode = ReasonCode.userDisconnected + let reason = SessionType.Reason(code: reasonCode.code, message: reasonCode.message) + logger.debug("Will delete pairing for reason: message: \(reason.message) code: \(reason.code)") + try await networkingInteractor.request(.wcSessionDelete(reason), onTopic: topic) + pairingStorage.delete(topic: topic) + kms.deleteSymmetricKey(for: topic) + networkingInteractor.unsubscribe(topic: topic) + } +} + diff --git a/Sources/WalletConnectSign/Engine/Common/DeleteSessionService.swift b/Sources/WalletConnectSign/Engine/Common/DeleteSessionService.swift new file mode 100644 index 000000000..561af3507 --- /dev/null +++ b/Sources/WalletConnectSign/Engine/Common/DeleteSessionService.swift @@ -0,0 +1,30 @@ +import Foundation +import WalletConnectKMS +import WalletConnectUtils + +class DeleteSessionService { + private let networkingInteractor: NetworkInteracting + private let kms: KeyManagementServiceProtocol + private let sessionStore: WCSessionStorage + private let logger: ConsoleLogging + + init(networkingInteractor: NetworkInteracting, + kms: KeyManagementServiceProtocol, + sessionStore: WCSessionStorage, + logger: ConsoleLogging) { + self.networkingInteractor = networkingInteractor + self.kms = kms + self.sessionStore = sessionStore + self.logger = logger + } + + func delete(topic: String) async throws { + let reasonCode = ReasonCode.userDisconnected + let reason = SessionType.Reason(code: reasonCode.code, message: reasonCode.message) + logger.debug("Will delete session for reason: message: \(reason.message) code: \(reason.code)") + try await networkingInteractor.request(.wcSessionDelete(reason), onTopic: topic) + sessionStore.delete(topic: topic) + kms.deleteSymmetricKey(for: topic) + networkingInteractor.unsubscribe(topic: topic) + } +} diff --git a/Sources/WalletConnectSign/Engine/Common/DisconnectService.swift b/Sources/WalletConnectSign/Engine/Common/DisconnectService.swift new file mode 100644 index 000000000..d0b417a7f --- /dev/null +++ b/Sources/WalletConnectSign/Engine/Common/DisconnectService.swift @@ -0,0 +1,33 @@ +import Foundation +import WalletConnectPairing + +class DisconnectService { + enum Errors: Error { + case objectForTopicNotFound + } + + private let deletePairingService: DeletePairingService + private let deleteSessionService: DeleteSessionService + private let pairingStorage: WCPairingStorage + private let sessionStorage: WCSessionStorage + + init(deletePairingService: DeletePairingService, + deleteSessionService: DeleteSessionService, + pairingStorage: WCPairingStorage, + sessionStorage: WCSessionStorage) { + self.deletePairingService = deletePairingService + self.deleteSessionService = deleteSessionService + self.pairingStorage = pairingStorage + self.sessionStorage = sessionStorage + } + + func disconnect(topic: String) async throws { + if pairingStorage.hasPairing(forTopic: topic) { + try await deletePairingService.delete(topic: topic) + } else if sessionStorage.hasSession(forTopic: topic) { + try await deleteSessionService.delete(topic: topic) + } else { + throw Errors.objectForTopicNotFound + } + } +} diff --git a/Sources/WalletConnectSign/Engine/Common/SessionEngine.swift b/Sources/WalletConnectSign/Engine/Common/SessionEngine.swift index 80f255b0a..a1197c8e1 100644 --- a/Sources/WalletConnectSign/Engine/Common/SessionEngine.swift +++ b/Sources/WalletConnectSign/Engine/Common/SessionEngine.swift @@ -44,15 +44,6 @@ final class SessionEngine { sessionStore.getAll().map {$0.publicRepresentation()} } - func delete(topic: String) async throws { - let reasonCode = ReasonCode.userDisconnected - let reason = SessionType.Reason(code: reasonCode.code, message: reasonCode.message) - logger.debug("Will delete session for reason: message: \(reason.message) code: \(reason.code)") - try await networkingInteractor.request(.wcSessionDelete(reason), onTopic: topic) - sessionStore.delete(topic: topic) - networkingInteractor.unsubscribe(topic: topic) - } - func ping(topic: String, completion: @escaping (Result) -> Void) { guard sessionStore.hasSession(forTopic: topic) else { logger.debug("Could not find session to ping for topic \(topic)") diff --git a/Sources/WalletConnectSign/Sign/SignClient.swift b/Sources/WalletConnectSign/Sign/SignClient.swift index d43546582..befbca947 100644 --- a/Sources/WalletConnectSign/Sign/SignClient.swift +++ b/Sources/WalletConnectSign/Sign/SignClient.swift @@ -91,6 +91,7 @@ public final class SignClient { private let pairEngine: PairEngine private let sessionEngine: SessionEngine private let approveEngine: ApproveEngine + private let disconnectService: DisconnectService private let nonControllerSessionStateMachine: NonControllerSessionStateMachine private let controllerSessionStateMachine: ControllerSessionStateMachine private let history: JsonRpcHistory @@ -119,6 +120,7 @@ public final class SignClient { approveEngine: ApproveEngine, nonControllerSessionStateMachine: NonControllerSessionStateMachine, controllerSessionStateMachine: ControllerSessionStateMachine, + disconnectService: DisconnectService, history: JsonRpcHistory, cleanupService: CleanupService ) { @@ -132,7 +134,7 @@ public final class SignClient { self.controllerSessionStateMachine = controllerSessionStateMachine self.history = history self.cleanupService = cleanupService - + self.disconnectService = disconnectService setUpConnectionObserving() setUpEnginesCallbacks() } @@ -267,7 +269,7 @@ public final class SignClient { /// - Parameters: /// - topic: Session topic that you want to delete public func disconnect(topic: String) async throws { - try await sessionEngine.delete(topic: topic) + try await disconnectService.disconnect(topic: topic) } /// Query sessions diff --git a/Sources/WalletConnectSign/Sign/SignClientFactory.swift b/Sources/WalletConnectSign/Sign/SignClientFactory.swift index 8ab60ee52..9a0412ad4 100644 --- a/Sources/WalletConnectSign/Sign/SignClientFactory.swift +++ b/Sources/WalletConnectSign/Sign/SignClientFactory.swift @@ -38,6 +38,9 @@ public struct SignClientFactory { let pairEngine = PairEngine(networkingInteractor: networkingInteractor, kms: kms, pairingStore: pairingStore) let approveEngine = ApproveEngine(networkingInteractor: networkingInteractor, proposalPayloadsStore: proposalPayloadsStore, sessionToPairingTopic: sessionToPairingTopic, metadata: metadata, kms: kms, logger: logger, pairingStore: pairingStore, sessionStore: sessionStore) let cleanupService = CleanupService(pairingStore: pairingStore, sessionStore: sessionStore, kms: kms, sessionToPairingTopic: sessionToPairingTopic) + let deletePairingService = DeletePairingService(networkingInteractor: networkingInteractor, kms: kms, pairingStorage: pairingStore, logger: logger) + let deleteSessionService = DeleteSessionService(networkingInteractor: networkingInteractor, kms: kms, sessionStore: sessionStore, logger: logger) + let disconnectService = DisconnectService(deletePairingService: deletePairingService, deleteSessionService: deleteSessionService, pairingStorage: pairingStore, sessionStorage: sessionStore) let client = SignClient( logger: logger, @@ -47,11 +50,10 @@ public struct SignClientFactory { sessionEngine: sessionEngine, approveEngine: approveEngine, nonControllerSessionStateMachine: nonControllerSessionStateMachine, - controllerSessionStateMachine: controllerSessionStateMachine, + controllerSessionStateMachine: controllerSessionStateMachine, disconnectService: disconnectService, history: history, cleanupService: cleanupService ) - return client } } From 1895acb57e67131662842e82acd1182f3d65ab9c Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 5 Sep 2022 09:39:10 +0200 Subject: [PATCH 10/13] run lint --- Package.swift | 2 +- Sources/Auth/Services/Common/DeletePairingService.swift | 1 - Sources/Chat/ProtocolServices/Common/MessagingService.swift | 2 +- Sources/WalletConnectKMS/Serialiser/Serializer.swift | 2 +- .../WalletConnectSign/Engine/Common/DeletePairingService.swift | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index a562eca58..893eb9338 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( targets: ["WalletConnectRouter"]), .library( name: "WalletConnectNetworking", - targets: ["WalletConnectNetworking"]), + targets: ["WalletConnectNetworking"]) ], dependencies: [ .package(url: "https://github.com/flypaper0/Web3.swift", .branch("feature/eip-155")) diff --git a/Sources/Auth/Services/Common/DeletePairingService.swift b/Sources/Auth/Services/Common/DeletePairingService.swift index d28546534..0b0cc4919 100644 --- a/Sources/Auth/Services/Common/DeletePairingService.swift +++ b/Sources/Auth/Services/Common/DeletePairingService.swift @@ -1,4 +1,3 @@ - import Foundation import WalletConnectNetworking import JSONRPC diff --git a/Sources/Chat/ProtocolServices/Common/MessagingService.swift b/Sources/Chat/ProtocolServices/Common/MessagingService.swift index eaeaf061e..a672fe386 100644 --- a/Sources/Chat/ProtocolServices/Common/MessagingService.swift +++ b/Sources/Chat/ProtocolServices/Common/MessagingService.swift @@ -43,7 +43,7 @@ class MessagingService { private func setUpResponseHandling() { networkingInteractor.responsePublisher - .sink { [unowned self] payload in + .sink { [unowned self] _ in logger.debug("Received Message response") }.store(in: &publishers) } diff --git a/Sources/WalletConnectKMS/Serialiser/Serializer.swift b/Sources/WalletConnectKMS/Serialiser/Serializer.swift index d58050137..742ddf2de 100644 --- a/Sources/WalletConnectKMS/Serialiser/Serializer.swift +++ b/Sources/WalletConnectKMS/Serialiser/Serializer.swift @@ -62,7 +62,7 @@ public class Serializer: Serializing { private func handleType1Envelope(_ topic: String, peerPubKey: Data, sealbox: Data) throws -> T { guard let selfPubKey = kms.getPublicKey(for: topic) else { throw Errors.publicKeyForTopicNotFound } - + let agreementKeys = try kms.performKeyAgreement(selfPublicKey: selfPubKey, peerPublicKey: peerPubKey.toHexString()) let decodedType: T = try decode(sealbox: sealbox, symmetricKey: agreementKeys.sharedKey.rawRepresentation) let newTopic = agreementKeys.derivedTopic() diff --git a/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift b/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift index b2e260b0a..a6324481e 100644 --- a/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift +++ b/Sources/WalletConnectSign/Engine/Common/DeletePairingService.swift @@ -29,4 +29,3 @@ class DeletePairingService { networkingInteractor.unsubscribe(topic: topic) } } - From afec45aee61c4e5d6a444a5225163d7b1a02843d Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 5 Sep 2022 12:45:54 +0200 Subject: [PATCH 11/13] after merge fix --- .../NetworkInteractor.swift | 14 -- .../NetworkingInteractor.swift | 178 ------------------ 2 files changed, 192 deletions(-) delete mode 100644 Sources/WalletConnectNetworking/NetworkingInteractor.swift diff --git a/Sources/WalletConnectNetworking/NetworkInteractor.swift b/Sources/WalletConnectNetworking/NetworkInteractor.swift index 7ae5f3c5f..13859ead6 100644 --- a/Sources/WalletConnectNetworking/NetworkInteractor.swift +++ b/Sources/WalletConnectNetworking/NetworkInteractor.swift @@ -12,16 +12,6 @@ public class NetworkingInteractor: NetworkInteracting { private let rpcHistory: RPCHistory private let logger: ConsoleLogging -<<<<<<< HEAD:Sources/WalletConnectNetworking/NetworkingInteractor.swift - private let requestPublisherSubject = PassthroughSubject() - private let responsePublisherSubject = PassthroughSubject() - - public var requestPublisher: AnyPublisher { - requestPublisherSubject.eraseToAnyPublisher() - } - - public var responsePublisher: AnyPublisher { -======= private let requestPublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest), Never>() private let responsePublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest, response: RPCResponse), Never>() @@ -30,7 +20,6 @@ public class NetworkingInteractor: NetworkInteracting { } private var responsePublisher: AnyPublisher<(topic: String, request: RPCRequest, response: RPCResponse), Never> { ->>>>>>> 7cb497caa4e4587bb940bd35ece55b709f14aac5:Sources/WalletConnectNetworking/NetworkInteractor.swift responsePublisherSubject.eraseToAnyPublisher() } @@ -67,8 +56,6 @@ public class NetworkingInteractor: NetworkInteracting { } } -<<<<<<< HEAD:Sources/WalletConnectNetworking/NetworkingInteractor.swift -======= public func requestSubscription(on request: ProtocolMethod) -> AnyPublisher, Never> { return requestPublisher .filter { $0.request.method == request.method } @@ -102,7 +89,6 @@ public class NetworkingInteractor: NetworkInteracting { .eraseToAnyPublisher() } ->>>>>>> 7cb497caa4e4587bb940bd35ece55b709f14aac5:Sources/WalletConnectNetworking/NetworkInteractor.swift public func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { try rpcHistory.set(request, forTopic: topic, emmitedBy: .local) let message = try! serializer.serialize(topic: topic, encodable: request, envelopeType: envelopeType) diff --git a/Sources/WalletConnectNetworking/NetworkingInteractor.swift b/Sources/WalletConnectNetworking/NetworkingInteractor.swift deleted file mode 100644 index 7ae5f3c5f..000000000 --- a/Sources/WalletConnectNetworking/NetworkingInteractor.swift +++ /dev/null @@ -1,178 +0,0 @@ -import Foundation -import Combine -import JSONRPC -import WalletConnectRelay -import WalletConnectUtils -import WalletConnectKMS - -public class NetworkingInteractor: NetworkInteracting { - private var publishers = Set() - private let relayClient: RelayClient - private let serializer: Serializing - private let rpcHistory: RPCHistory - private let logger: ConsoleLogging - -<<<<<<< HEAD:Sources/WalletConnectNetworking/NetworkingInteractor.swift - private let requestPublisherSubject = PassthroughSubject() - private let responsePublisherSubject = PassthroughSubject() - - public var requestPublisher: AnyPublisher { - requestPublisherSubject.eraseToAnyPublisher() - } - - public var responsePublisher: AnyPublisher { -======= - private let requestPublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest), Never>() - private let responsePublisherSubject = PassthroughSubject<(topic: String, request: RPCRequest, response: RPCResponse), Never>() - - private var requestPublisher: AnyPublisher<(topic: String, request: RPCRequest), Never> { - requestPublisherSubject.eraseToAnyPublisher() - } - - private var responsePublisher: AnyPublisher<(topic: String, request: RPCRequest, response: RPCResponse), Never> { ->>>>>>> 7cb497caa4e4587bb940bd35ece55b709f14aac5:Sources/WalletConnectNetworking/NetworkInteractor.swift - responsePublisherSubject.eraseToAnyPublisher() - } - - public var socketConnectionStatusPublisher: AnyPublisher - - public init( - relayClient: RelayClient, - serializer: Serializing, - logger: ConsoleLogging, - rpcHistory: RPCHistory - ) { - self.relayClient = relayClient - self.serializer = serializer - self.rpcHistory = rpcHistory - self.logger = logger - self.socketConnectionStatusPublisher = relayClient.socketConnectionStatusPublisher - relayClient.messagePublisher.sink { [unowned self] (topic, message) in - manageSubscription(topic, message) - } - .store(in: &publishers) - } - - public func subscribe(topic: String) async throws { - try await relayClient.subscribe(topic: topic) - } - - public func unsubscribe(topic: String) { - relayClient.unsubscribe(topic: topic) { [unowned self] error in - if let error = error { - logger.error(error) - } else { - rpcHistory.deleteAll(forTopic: topic) - } - } - } - -<<<<<<< HEAD:Sources/WalletConnectNetworking/NetworkingInteractor.swift -======= - public func requestSubscription(on request: ProtocolMethod) -> AnyPublisher, Never> { - return requestPublisher - .filter { $0.request.method == request.method } - .compactMap { topic, rpcRequest in - guard let id = rpcRequest.id, let request = try? rpcRequest.params?.get(Request.self) else { return nil } - return RequestSubscriptionPayload(id: id, topic: topic, request: request) - } - .eraseToAnyPublisher() - } - - public func responseSubscription(on request: ProtocolMethod) -> AnyPublisher, Never> { - return responsePublisher - .filter { $0.request.method == request.method } - .compactMap { topic, rpcRequest, rpcResponse in - guard - let id = rpcRequest.id, - let request = try? rpcRequest.params?.get(Request.self), - let response = try? rpcResponse.result?.get(Response.self) else { return nil } - return ResponseSubscriptionPayload(id: id, topic: topic, request: request, response: response) - } - .eraseToAnyPublisher() - } - - public func responseErrorSubscription(on request: ProtocolMethod) -> AnyPublisher { - return responsePublisher - .filter { $0.request.method == request.method } - .compactMap { (_, _, rpcResponse) in - guard let id = rpcResponse.id, let error = rpcResponse.error else { return nil } - return ResponseSubscriptionErrorPayload(id: id, error: error) - } - .eraseToAnyPublisher() - } - ->>>>>>> 7cb497caa4e4587bb940bd35ece55b709f14aac5:Sources/WalletConnectNetworking/NetworkInteractor.swift - public func request(_ request: RPCRequest, topic: String, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { - try rpcHistory.set(request, forTopic: topic, emmitedBy: .local) - let message = try! serializer.serialize(topic: topic, encodable: request, envelopeType: envelopeType) - try await relayClient.publish(topic: topic, payload: message, tag: tag) - } - - /// Completes with an acknowledgement from the relay network. - /// completes with error if networking client was not able to send a message - /// TODO - relay client should provide async function - continualion should be removed from here - public func requestNetworkAck(_ request: RPCRequest, topic: String, tag: Int) async throws { - do { - try rpcHistory.set(request, forTopic: topic, emmitedBy: .local) - let message = try serializer.serialize(topic: topic, encodable: request) - return try await withCheckedThrowingContinuation { continuation in - relayClient.publish(topic: topic, payload: message, tag: tag) { error in - if let error = error { - continuation.resume(throwing: error) - } else { - continuation.resume() - } - } - } - } catch { - logger.error(error) - } - } - - public func respond(topic: String, response: RPCResponse, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { - try rpcHistory.resolve(response) - let message = try! serializer.serialize(topic: topic, encodable: response, envelopeType: envelopeType) - try await relayClient.publish(topic: topic, payload: message, tag: tag) - } - - public func respondSuccess(topic: String, requestId: RPCID, tag: Int, envelopeType: Envelope.EnvelopeType) async throws { - let response = RPCResponse(id: requestId, result: true) - try await respond(topic: topic, response: response, tag: tag, envelopeType: envelopeType) - } - - public func respondError(topic: String, requestId: RPCID, tag: Int, reason: Reason, envelopeType: Envelope.EnvelopeType) async throws { - let error = JSONRPCError(code: reason.code, message: reason.message) - let response = RPCResponse(id: requestId, error: error) - try await respond(topic: topic, response: response, tag: tag, envelopeType: envelopeType) - } - - private func manageSubscription(_ topic: String, _ encodedEnvelope: String) { - if let deserializedJsonRpcRequest: RPCRequest = serializer.tryDeserialize(topic: topic, encodedEnvelope: encodedEnvelope) { - handleRequest(topic: topic, request: deserializedJsonRpcRequest) - } else if let response: RPCResponse = serializer.tryDeserialize(topic: topic, encodedEnvelope: encodedEnvelope) { - handleResponse(response: response) - } else { - logger.debug("Networking Interactor - Received unknown object type from networking relay") - } - } - - private func handleRequest(topic: String, request: RPCRequest) { - do { - try rpcHistory.set(request, forTopic: topic, emmitedBy: .remote) - requestPublisherSubject.send((topic, request)) - } catch { - logger.debug(error) - } - } - - private func handleResponse(response: RPCResponse) { - do { - try rpcHistory.resolve(response) - let record = rpcHistory.get(recordId: response.id!)! - responsePublisherSubject.send((record.topic, record.request, response)) - } catch { - logger.debug("Handle json rpc response error: \(error)") - } - } -} From 3f9b42b3a0099ccf6edb9f9c61e5bd700e969449 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 5 Sep 2022 13:34:52 +0200 Subject: [PATCH 12/13] fix tags --- ...tocolMethods.swift => AuthProtocolMethod.swift} | 7 ++++++- Sources/Auth/Services/App/AppRequestService.swift | 2 +- .../Services/Wallet/WalletRequestSubscriber.swift | 4 ++-- .../Services/Wallet/WalletRespondService.swift | 4 ++-- Sources/Auth/Types/AuthProtocolMethod.swift | 14 -------------- .../ProtocolServices/Common/MessagingService.swift | 4 ++-- .../Invitee/InvitationHandlingService.swift | 4 ++-- .../ProtocolServices/Inviter/InviteService.swift | 2 +- Sources/Chat/Types/ChatProtocolMethod.swift | 13 +++++++++++-- .../WalletConnectNetworking/ProtocolMethod.swift | 3 ++- 10 files changed, 29 insertions(+), 28 deletions(-) rename Sources/Auth/{AuthProtocolMethods.swift => AuthProtocolMethod.swift} (80%) delete mode 100644 Sources/Auth/Types/AuthProtocolMethod.swift diff --git a/Sources/Auth/AuthProtocolMethods.swift b/Sources/Auth/AuthProtocolMethod.swift similarity index 80% rename from Sources/Auth/AuthProtocolMethods.swift rename to Sources/Auth/AuthProtocolMethod.swift index b4ce15058..c3df72dae 100644 --- a/Sources/Auth/AuthProtocolMethods.swift +++ b/Sources/Auth/AuthProtocolMethod.swift @@ -1,10 +1,15 @@ import Foundation +import WalletConnectNetworking -enum AuthProtocolMethods: String { +enum AuthProtocolMethod: String, ProtocolMethod { case authRequest = "wc_authRequest" case pairingDelete = "wc_pairingDelete" case pairingPing = "wc_pairingPing" + var method: String { + return self.rawValue + } + var requestTag: Int { switch self { case .authRequest: diff --git a/Sources/Auth/Services/App/AppRequestService.swift b/Sources/Auth/Services/App/AppRequestService.swift index e1c988eac..da88c993a 100644 --- a/Sources/Auth/Services/App/AppRequestService.swift +++ b/Sources/Auth/Services/App/AppRequestService.swift @@ -30,7 +30,7 @@ actor AppRequestService { let request = RPCRequest(method: "wc_authRequest", params: params) try kms.setPublicKey(publicKey: pubKey, for: responseTopic) logger.debug("AppRequestService: Subscribibg for response topic: \(responseTopic)") - try await networkingInteractor.requestNetworkAck(request, topic: topic, tag: AuthProtocolMethod.request.tag) + try await networkingInteractor.requestNetworkAck(request, topic: topic, tag: AuthProtocolMethod.authRequest.responseTag) try await networkingInteractor.subscribe(topic: responseTopic) } } diff --git a/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift b/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift index 41d74d8a7..660b88a72 100644 --- a/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift +++ b/Sources/Auth/Services/Wallet/WalletRequestSubscriber.swift @@ -30,7 +30,7 @@ class WalletRequestSubscriber { private func subscribeForRequest() { guard let address = address else { return } - networkingInteractor.requestSubscription(on: AuthProtocolMethod.request) + networkingInteractor.requestSubscription(on: AuthProtocolMethod.authRequest) .sink { [unowned self] (payload: RequestSubscriptionPayload) in logger.debug("WalletRequestSubscriber: Received request") let message = messageFormatter.formatMessage(from: payload.request.payloadParams, address: address) @@ -42,7 +42,7 @@ class WalletRequestSubscriber { guard let pubKey = kms.getAgreementSecret(for: topic)?.publicKey else { return logger.error("Agreement key for topic \(topic) not found") } - let tag = AuthProtocolMethod.request.tag + let tag = AuthProtocolMethod.authRequest.responseTag let envelopeType = Envelope.EnvelopeType.type1(pubKey: pubKey.rawRepresentation) Task(priority: .high) { diff --git a/Sources/Auth/Services/Wallet/WalletRespondService.swift b/Sources/Auth/Services/Wallet/WalletRespondService.swift index ae87580f4..2f3ddad63 100644 --- a/Sources/Auth/Services/Wallet/WalletRespondService.swift +++ b/Sources/Auth/Services/Wallet/WalletRespondService.swift @@ -33,7 +33,7 @@ actor WalletRespondService { let didpkh = DIDPKH(account: account) let cacao = CacaoFormatter().format(authRequestParams, signature, didpkh) let response = RPCResponse(id: requestId, result: cacao) - try await networkingInteractor.respond(topic: topic, response: response, tag: AuthProtocolMethod.request.tag, envelopeType: .type1(pubKey: keys.publicKey.rawRepresentation)) + try await networkingInteractor.respond(topic: topic, response: response, tag: AuthProtocolMethod.authRequest.responseTag, envelopeType: .type1(pubKey: keys.publicKey.rawRepresentation)) } func respondError(requestId: RPCID) async throws { @@ -42,7 +42,7 @@ actor WalletRespondService { try kms.setAgreementSecret(keys, topic: topic) - let tag = AuthProtocolMethod.request.tag + let tag = AuthProtocolMethod.authRequest.responseTag let error = AuthError.userRejeted let envelopeType = Envelope.EnvelopeType.type1(pubKey: keys.publicKey.rawRepresentation) try await networkingInteractor.respondError(topic: topic, requestId: requestId, tag: tag, reason: error, envelopeType: envelopeType) diff --git a/Sources/Auth/Types/AuthProtocolMethod.swift b/Sources/Auth/Types/AuthProtocolMethod.swift deleted file mode 100644 index 37ff013d3..000000000 --- a/Sources/Auth/Types/AuthProtocolMethod.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation -import WalletConnectNetworking - -enum AuthProtocolMethod: ProtocolMethod { - case request - - var method: String { - return "wc_authRequest" - } - - var tag: Int { - return 3001 - } -} diff --git a/Sources/Chat/ProtocolServices/Common/MessagingService.swift b/Sources/Chat/ProtocolServices/Common/MessagingService.swift index d9fc9e772..20edfb6b5 100644 --- a/Sources/Chat/ProtocolServices/Common/MessagingService.swift +++ b/Sources/Chat/ProtocolServices/Common/MessagingService.swift @@ -34,7 +34,7 @@ class MessagingService { let timestamp = Int64(Date().timeIntervalSince1970 * 1000) let message = Message(topic: topic, message: messageString, authorAccount: authorAccount, timestamp: timestamp) let request = RPCRequest(method: ChatProtocolMethod.message.method, params: message) - try await networkingInteractor.request(request, topic: topic, tag: ChatProtocolMethod.message.tag) + try await networkingInteractor.request(request, topic: topic, tag: ChatProtocolMethod.message.requestTag) Task(priority: .background) { await messagesStore.add(message) onMessage?(message) @@ -59,7 +59,7 @@ class MessagingService { private func handleMessage(_ message: Message, topic: String, requestId: RPCID) { Task(priority: .background) { - try await networkingInteractor.respondSuccess(topic: topic, requestId: requestId, tag: ChatProtocolMethod.message.tag) + try await networkingInteractor.respondSuccess(topic: topic, requestId: requestId, tag: ChatProtocolMethod.message.responseTag) await messagesStore.add(message) logger.debug("Received message") onMessage?(message) diff --git a/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift b/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift index 85509e248..c6dd9aede 100644 --- a/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift +++ b/Sources/Chat/ProtocolServices/Invitee/InvitationHandlingService.swift @@ -47,7 +47,7 @@ class InvitationHandlingService { let response = RPCResponse(id: payload.id, result: inviteResponse) let responseTopic = try getInviteResponseTopic(requestTopic: payload.topic, invite: payload.request) - try await networkingInteractor.respond(topic: responseTopic, response: response, tag: ChatProtocolMethod.invite.tag) + try await networkingInteractor.respond(topic: responseTopic, response: response, tag: ChatProtocolMethod.invite.responseTag) let threadAgreementKeys = try kms.performKeyAgreement(selfPublicKey: selfThreadPubKey, peerPublicKey: payload.request.publicKey) let threadTopic = threadAgreementKeys.derivedTopic() @@ -71,7 +71,7 @@ class InvitationHandlingService { let responseTopic = try getInviteResponseTopic(requestTopic: payload.topic, invite: payload.request) - try await networkingInteractor.respondError(topic: responseTopic, requestId: payload.id, tag: ChatProtocolMethod.invite.tag, reason: ChatError.userRejected) + try await networkingInteractor.respondError(topic: responseTopic, requestId: payload.id, tag: ChatProtocolMethod.invite.responseTag, reason: ChatError.userRejected) invitePayloadStore.delete(forKey: inviteId) } diff --git a/Sources/Chat/ProtocolServices/Inviter/InviteService.swift b/Sources/Chat/ProtocolServices/Inviter/InviteService.swift index d04308f5e..514138042 100644 --- a/Sources/Chat/ProtocolServices/Inviter/InviteService.swift +++ b/Sources/Chat/ProtocolServices/Inviter/InviteService.swift @@ -50,7 +50,7 @@ class InviteService { try kms.setSymmetricKey(symKeyI.sharedKey, for: responseTopic) try await networkingInteractor.subscribe(topic: responseTopic) - try await networkingInteractor.request(request, topic: inviteTopic, tag: ChatProtocolMethod.invite.tag, envelopeType: .type1(pubKey: selfPubKeyY.rawRepresentation)) + try await networkingInteractor.request(request, topic: inviteTopic, tag: ChatProtocolMethod.invite.requestTag, envelopeType: .type1(pubKey: selfPubKeyY.rawRepresentation)) logger.debug("invite sent on topic: \(inviteTopic)") } diff --git a/Sources/Chat/Types/ChatProtocolMethod.swift b/Sources/Chat/Types/ChatProtocolMethod.swift index 1566f375c..a32e5d4bf 100644 --- a/Sources/Chat/Types/ChatProtocolMethod.swift +++ b/Sources/Chat/Types/ChatProtocolMethod.swift @@ -5,14 +5,23 @@ enum ChatProtocolMethod: ProtocolMethod { case invite case message - var tag: Int { + var requestTag: Int { switch self { case .invite: - return 2002 + return 2000 case .message: return 2002 } } + + var responseTag: Int { + switch self { + case .invite: + return 2001 + case .message: + return 2003 + } + } var method: String { switch self { diff --git a/Sources/WalletConnectNetworking/ProtocolMethod.swift b/Sources/WalletConnectNetworking/ProtocolMethod.swift index 1809ad6ba..dea8bd255 100644 --- a/Sources/WalletConnectNetworking/ProtocolMethod.swift +++ b/Sources/WalletConnectNetworking/ProtocolMethod.swift @@ -2,5 +2,6 @@ import Foundation public protocol ProtocolMethod { var method: String { get } - var tag: Int { get } + var requestTag: Int { get } + var responseTag: Int { get } } From 8a7e004a2e024e2a2667aa0e53fe9dd733f53fbe Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Mon, 5 Sep 2022 13:35:31 +0200 Subject: [PATCH 13/13] update --- Sources/Auth/Services/App/AppRespondSubscriber.swift | 4 ++-- Sources/Auth/Services/Common/DeletePairingService.swift | 4 ++-- Tests/AuthTests/WalletRequestSubscriberTests.swift | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Auth/Services/App/AppRespondSubscriber.swift b/Sources/Auth/Services/App/AppRespondSubscriber.swift index 61477b712..5c59d1128 100644 --- a/Sources/Auth/Services/App/AppRespondSubscriber.swift +++ b/Sources/Auth/Services/App/AppRespondSubscriber.swift @@ -32,13 +32,13 @@ class AppRespondSubscriber { } private func subscribeForResponse() { - networkingInteractor.responseErrorSubscription(on: AuthProtocolMethod.request) + networkingInteractor.responseErrorSubscription(on: AuthProtocolMethod.authRequest) .sink { [unowned self] payload in guard let error = AuthError(code: payload.error.code) else { return } onResponse?(payload.id, .failure(error)) }.store(in: &publishers) - networkingInteractor.responseSubscription(on: AuthProtocolMethod.request) + networkingInteractor.responseSubscription(on: AuthProtocolMethod.authRequest) .sink { [unowned self] (payload: ResponseSubscriptionPayload) in activatePairingIfNeeded(id: payload.id) diff --git a/Sources/Auth/Services/Common/DeletePairingService.swift b/Sources/Auth/Services/Common/DeletePairingService.swift index 0b0cc4919..721bdc81f 100644 --- a/Sources/Auth/Services/Common/DeletePairingService.swift +++ b/Sources/Auth/Services/Common/DeletePairingService.swift @@ -28,8 +28,8 @@ class DeletePairingService { guard pairingStorage.hasPairing(forTopic: topic) else { throw Errors.pairingNotFound} let reason = AuthError.userDisconnected logger.debug("Will delete pairing for reason: message: \(reason.message) code: \(reason.code)") - let request = RPCRequest(method: AuthProtocolMethods.pairingDelete.rawValue, params: reason) - try await networkingInteractor.request(request, topic: topic, tag: AuthProtocolMethods.pairingDelete.requestTag) + let request = RPCRequest(method: AuthProtocolMethod.pairingDelete.rawValue, params: reason) + try await networkingInteractor.request(request, topic: topic, tag: AuthProtocolMethod.pairingDelete.requestTag) pairingStorage.delete(topic: topic) kms.deleteSymmetricKey(for: topic) networkingInteractor.unsubscribe(topic: topic) diff --git a/Tests/AuthTests/WalletRequestSubscriberTests.swift b/Tests/AuthTests/WalletRequestSubscriberTests.swift index 5a7f94649..4a2062f61 100644 --- a/Tests/AuthTests/WalletRequestSubscriberTests.swift +++ b/Tests/AuthTests/WalletRequestSubscriberTests.swift @@ -35,7 +35,7 @@ class WalletRequestSubscriberTests: XCTestCase { messageExpectation.fulfill() } - let request = RPCRequest(method: AuthProtocolMethod.request.method, params: AuthRequestParams.stub(id: expectedRequestId), id: expectedRequestId.right!) + let request = RPCRequest(method: AuthProtocolMethod.authRequest.method, params: AuthRequestParams.stub(id: expectedRequestId), id: expectedRequestId.right!) networkingInteractor.requestPublisherSubject.send(("123", request)) wait(for: [messageExpectation], timeout: defaultTimeout)