Skip to content

Commit

Permalink
Merge branch 'monorepo' of github.com:reown-com/reown-swift into acco…
Browse files Browse the repository at this point in the history
…unt_integration
  • Loading branch information
llbartekll committed Sep 12, 2024
2 parents 487e34c + fea452b commit f131d7f
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ jobs:

- name: Lint CocoaPods
run: |
pod lib lint --verbose --no-clean --quick --allow-warnings --platforms=ios WalletConnectSwiftV2.podspec
pod lib lint --verbose --no-clean --quick --allow-warnings --platforms=ios reown-swift.podspec
14 changes: 4 additions & 10 deletions Example/ExampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2426,11 +2426,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = PNDecryptionService/PNDecryptionService.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PNDecryptionService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = PNDecryptionService;
Expand All @@ -2445,7 +2443,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp.PNDecryptionService;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.walletapp.PNDecryptionService";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -2571,11 +2568,9 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = WalletApp/WalletApp.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22;
DEVELOPMENT_TEAM = W5R8AG9K22;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WalletApp/Other/Info.plist;
Expand All @@ -2595,7 +2590,6 @@
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.walletapp";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation

actor WalletPairService {
enum Errors: Error {
case noPendingRequestsForPairing(topic: String)
case networkNotConnected
}

Expand Down Expand Up @@ -70,13 +71,15 @@ extension WalletPairService {
guard let pairing = pairingStorage.getPairing(forTopic: topic), pairing.requestReceived else {
return false
}

let pendingRequests = history.getPending()
.compactMap { record -> RPCRequest? in
(record.topic == pairing.topic) ? record.request : nil
}

guard !pendingRequests.isEmpty else { return false }
guard !pendingRequests.isEmpty else {
throw Errors.noPendingRequestsForPairing(topic: topic)
}
pendingRequests.forEach { request in
eventsClient.saveTraceEvent(PairingExecutionTraceEvents.emitSessionProposal)
networkingInteractor.handleHistoryRequest(topic: topic, request: request)
Expand All @@ -103,6 +106,7 @@ extension WalletPairService {
extension WalletPairService.Errors: LocalizedError {
var errorDescription: String? {
switch self {
case .noPendingRequestsForPairing(let topic): return "No pending requests for pairing, topic: \(topic)"
case .networkNotConnected: return "Pairing failed. You seem to be offline"
}
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/WalletConnectRelay/Dispatching.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,26 @@ final class Dispatcher: NSObject, Dispatching {
}

func protectedSend(_ string: String, completion: @escaping (Error?) -> Void) {
logger.debug("will try to send a socket frame")
// Check if the socket is already connected and ready to send
if socket.isConnected && networkMonitor.isConnected {
logger.debug("sending a socket frame")
send(string, completion: completion)
return
}

logger.debug("Socket is not connected, will try to connect to send a frame")
// Start the connection process if not already connected
Task {
do {
// Await the connection handler to establish the connection
try await socketConnectionHandler.handleInternalConnect()

logger.debug("internal connect successful, will try to send a socket frame")
// If successful, send the message
send(string, completion: completion)
} catch {
logger.debug("failed to handle internal connect")
// If an error occurs during connection, complete with that error
completion(error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,23 @@ class AutomaticSocketConnectionHandler {

func connect() {
// Start the connection process
logger.debug("Starting connection process.")
isConnecting = true
socket.connect()
}

private func setUpSocketStatusObserving() {
logger.debug("Setting up socket status observing.")
socketStatusProvider.socketConnectionStatusPublisher
.sink { [unowned self] status in
switch status {
case .connected:
logger.debug("Socket connected.")
isConnecting = false
reconnectionAttempts = 0 // Reset reconnection attempts on successful connection
stopPeriodicReconnectionTimer() // Stop any ongoing periodic reconnection attempts
case .disconnected:
logger.debug("Socket disconnected.")
if isConnecting {
// Handle reconnection logic
handleFailedConnectionAndReconnectIfNeeded()
Expand All @@ -89,13 +93,18 @@ class AutomaticSocketConnectionHandler {
}

private func stopPeriodicReconnectionTimer() {
logger.debug("Stopping periodic reconnection timer.")
reconnectionTimer?.cancel()
reconnectionTimer = nil
}

private func startPeriodicReconnectionTimerIfNeeded() {
guard reconnectionTimer == nil else {return}
guard reconnectionTimer == nil else {
logger.debug("Reconnection timer is already running.")
return
}

logger.debug("Starting periodic reconnection timer.")
reconnectionTimer = DispatchSource.makeTimerSource(queue: concurrentQueue)
let initialDelay: DispatchTime = .now() + periodicReconnectionInterval

Expand All @@ -112,55 +121,69 @@ class AutomaticSocketConnectionHandler {
}

private func setUpStateObserving() {
logger.debug("Setting up app state observing.")
appStateObserver.onWillEnterBackground = { [unowned self] in
logger.debug("App will enter background. Registering background task.")
registerBackgroundTask()
}

appStateObserver.onWillEnterForeground = { [unowned self] in
logger.debug("App will enter foreground. Reconnecting if needed.")
reconnectIfNeeded()
}
}

private func setUpNetworkMonitoring() {
networkMonitor.networkConnectionStatusPublisher.sink { [unowned self] networkConnectionStatus in
if networkConnectionStatus == .connected {
reconnectIfNeeded()
logger.debug("Setting up network monitoring.")
networkMonitor.networkConnectionStatusPublisher
.sink { [unowned self] networkConnectionStatus in
if networkConnectionStatus == .connected {
logger.debug("Network connected. Reconnecting if needed.")
reconnectIfNeeded()
}
}
}
.store(in: &publishers)
.store(in: &publishers)
}

private func registerBackgroundTask() {
logger.debug("Registering background task.")
backgroundTaskRegistrar.register(name: "Finish Network Tasks") { [unowned self] in
endBackgroundTask()
}
}

private func endBackgroundTask() {
logger.debug("Ending background task. Disconnecting socket.")
socket.disconnect()
}

func reconnectIfNeeded() {
// Check if client has active subscriptions and only then attempt to reconnect
logger.debug("Checking if reconnection is needed.")
if !socket.isConnected && subscriptionsTracker.isSubscribed() {
logger.debug("Socket is not connected, but there are active subscriptions. Reconnecting...")
connect()
} else {
logger.debug("Will not attempt to reconnect")
}
}
var requestTimeout: TimeInterval = 15

var requestTimeout: TimeInterval = 15
}

// MARK: - SocketConnectionHandler

extension AutomaticSocketConnectionHandler: SocketConnectionHandler {
func handleInternalConnect() async throws {
logger.debug("Handling internal connection.")
let maxAttempts = maxImmediateAttempts
var attempts = 0
var isResumed = false // Track if continuation has been resumed
let requestTimeout = self.requestTimeout // Timeout set at the class level

// Start the connection process immediately if not already connecting
if !isConnecting {
logger.debug("Not already connecting. Starting connection.")
connect() // This will set isConnecting = true and attempt to connect
}

Expand All @@ -172,7 +195,10 @@ extension AutomaticSocketConnectionHandler: SocketConnectionHandler {
let connection = connectionStatusPublisher.connect()

// Ensure connection is canceled when done
defer { connection.cancel() }
defer {
logger.debug("Cancelling connection status publisher.")
connection.cancel()
}

// Use a Combine publisher to monitor disconnection and timeout
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
Expand All @@ -181,18 +207,20 @@ extension AutomaticSocketConnectionHandler: SocketConnectionHandler {
cancellable = connectionStatusPublisher
.setFailureType(to: NetworkError.self) // Set failure type to NetworkError
.timeout(.seconds(requestTimeout), scheduler: concurrentQueue, customError: { NetworkError.connectionFailed })
.sink(receiveCompletion: { completion in
.sink(receiveCompletion: { [unowned self] completion in
guard !isResumed else { return } // Ensure continuation is only resumed once
isResumed = true
cancellable?.cancel() // Cancel the subscription to prevent further events

// Handle only the failure case, as .finished is not expected to be meaningful here
if case .failure(let error) = completion {
logger.debug("Connection failed with error: \(error).")
continuation.resume(throwing: error) // Timeout or connection failure
}
}, receiveValue: { [unowned self] status in
guard !isResumed else { return } // Ensure continuation is only resumed once
if status == .connected {
logger.debug("Connection succeeded.")
isResumed = true
cancellable?.cancel() // Cancel the subscription to prevent further events
continuation.resume() // Successfully connected
Expand All @@ -201,6 +229,7 @@ extension AutomaticSocketConnectionHandler: SocketConnectionHandler {
logger.debug("Disconnection observed, incrementing attempts to \(attempts)")

if attempts >= maxAttempts {
logger.debug("Max attempts reached. Failing with connection error.")
isResumed = true
cancellable?.cancel() // Cancel the subscription to prevent further events
continuation.resume(throwing: NetworkError.connectionFailed)
Expand All @@ -214,15 +243,21 @@ extension AutomaticSocketConnectionHandler: SocketConnectionHandler {
}

func handleConnect() throws {
logger.debug("Manual connect requested but forbidden.")
throw Errors.manualSocketConnectionForbidden
}

func handleDisconnect(closeCode: URLSessionWebSocketTask.CloseCode) throws {
logger.debug("Manual disconnect requested but forbidden.")
throw Errors.manualSocketDisconnectionForbidden
}

func handleDisconnection() async {
guard await appStateObserver.currentState == .foreground else { return }
logger.debug("Handling disconnection.")
// guard await appStateObserver.currentState == .foreground else {
// logger.debug("App is not in foreground. No reconnection will be attempted.")
// return
// }
reconnectIfNeeded()
}
}
4 changes: 2 additions & 2 deletions Sources/WalletConnectSign/Engine/Common/ApproveEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ final class ApproveEngine {
sessionStore.setSession(session)

Task {
removePairing(pairingTopic: pairingTopic)
networkingInteractor.unsubscribe(topic: pairingTopic)
}
onSessionSettle?(session.publicRepresentation())
eventsClient.saveTraceEvent(SessionApproveExecutionTraceEvents.sessionSettleSuccess)
Expand Down Expand Up @@ -202,7 +202,7 @@ final class ApproveEngine {

if let pairingTopic = rpcHistory.get(recordId: payload.id)?.topic {
Task {
removePairing(pairingTopic: pairingTopic)
networkingInteractor.unsubscribe(topic: pairingTopic)
}
}

Expand Down

0 comments on commit f131d7f

Please sign in to comment.