summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ios/.swiftlint.yml1
-rw-r--r--ios/MullvadREST/ApiHandlers/RESTError.swift4
-rw-r--r--ios/MullvadREST/Transport/Direct/URLSessionTransport.swift9
-rw-r--r--ios/MullvadREST/Transport/Shadowsocks/ShadowsocksTransport.swift2
-rw-r--r--ios/MullvadREST/Transport/Socks5/URLSessionSocks5Transport.swift2
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj3
-rw-r--r--ios/MullvadVPN/Coordinators/AccountCoordinator.swift61
-rw-r--r--ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift2
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift1
-rw-r--r--ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift21
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift2
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift2
-rw-r--r--ios/MullvadVPN/Views/MullvadAlert.swift120
-rw-r--r--ios/MullvadVPN/Views/SpinnerActivityIndicatorView.swift2
-rw-r--r--ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift8
-rw-r--r--ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift2
-rw-r--r--ios/PacketTunnel/WireGuardAdapter/WireGuardAdapterError+Localization.swift6
-rw-r--r--ios/PacketTunnelCore/Actor/PacketTunnelActor.swift87
-rw-r--r--ios/Routing/Coordinator.swift2
-rw-r--r--ios/Routing/Router/ApplicationRouter.swift2
20 files changed, 204 insertions, 135 deletions
diff --git a/ios/.swiftlint.yml b/ios/.swiftlint.yml
index 8729b4a656..408738d853 100644
--- a/ios/.swiftlint.yml
+++ b/ios/.swiftlint.yml
@@ -23,6 +23,7 @@ excluded: # case-sensitive paths to ignore during linting. Takes precedence ove
- Build
- Configurations
- MullvadVPNScreenshots
+ - wireguard-apple
allow_zero_lintable_files: false
diff --git a/ios/MullvadREST/ApiHandlers/RESTError.swift b/ios/MullvadREST/ApiHandlers/RESTError.swift
index d1c02fa835..28f65651b9 100644
--- a/ios/MullvadREST/ApiHandlers/RESTError.swift
+++ b/ios/MullvadREST/ApiHandlers/RESTError.swift
@@ -32,8 +32,8 @@ extension REST {
case .createURLRequest:
return "Failure to create URL request."
- case .network:
- return "Network error."
+ case let .network(error):
+ return "Network error due to \(error.localizedDescription)."
case let .unhandledResponse(statusCode, serverResponse):
var str = "Failure to handle server response: HTTP/\(statusCode)."
diff --git a/ios/MullvadREST/Transport/Direct/URLSessionTransport.swift b/ios/MullvadREST/Transport/Direct/URLSessionTransport.swift
index ecfff2d930..d8ebda1921 100644
--- a/ios/MullvadREST/Transport/Direct/URLSessionTransport.swift
+++ b/ios/MullvadREST/Transport/Direct/URLSessionTransport.swift
@@ -9,7 +9,12 @@
import Foundation
import MullvadTypes
-extension URLSessionTask: Cancellable {}
+struct URLSessionTaskWrapper: Cancellable {
+ let task: URLSessionTask
+ func cancel() {
+ task.cancel()
+ }
+}
public final class URLSessionTransport: RESTTransport {
public var name: String {
@@ -28,6 +33,6 @@ public final class URLSessionTransport: RESTTransport {
) -> Cancellable {
let dataTask = urlSession.dataTask(with: request, completionHandler: completion)
dataTask.resume()
- return dataTask
+ return URLSessionTaskWrapper(task: dataTask)
}
}
diff --git a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksTransport.swift b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksTransport.swift
index 71f8e7cd16..dc2a67767a 100644
--- a/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksTransport.swift
+++ b/ios/MullvadREST/Transport/Shadowsocks/ShadowsocksTransport.swift
@@ -60,6 +60,6 @@ public final class ShadowsocksTransport: RESTTransport {
let dataTask = urlSession.dataTask(with: urlRequestCopy, completionHandler: completion)
dataTask.resume()
- return dataTask
+ return URLSessionTaskWrapper(task: dataTask)
}
}
diff --git a/ios/MullvadREST/Transport/Socks5/URLSessionSocks5Transport.swift b/ios/MullvadREST/Transport/Socks5/URLSessionSocks5Transport.swift
index bb408ccf59..43c0fc6c7e 100644
--- a/ios/MullvadREST/Transport/Socks5/URLSessionSocks5Transport.swift
+++ b/ios/MullvadREST/Transport/Socks5/URLSessionSocks5Transport.swift
@@ -108,6 +108,6 @@ public final class URLSessionSocks5Transport: RESTTransport, Sendable {
let dataTask = urlSession.dataTask(with: newRequest, completionHandler: completion)
dataTask.resume()
- return dataTask
+ return URLSessionTaskWrapper(task: dataTask)
}
}
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 113776ad9f..3a91d75af9 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -5917,10 +5917,11 @@
outputFileListPaths = (
);
outputPaths = (
+ "${DERIVED_FILE_DIR}/localization-cleanup-done.flag",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "# Run the following steps if the build configuration is NOT Debug\n# OR if the configuration is Staging (used for UITests).\nif [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$CONFIGURATION\" = \"Staging\" ]; then\n echo \"Removing non-English localizations for Release or Staging build\"\n find \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\" -type d -name \"*.lproj\" ! -name \"en.lproj\" -exec rm -r {} +\nfi\n";
+ shellScript = "# Run the following steps if the build configuration is NOT Debug\n# OR if the configuration is Staging (used for UITests).\nif [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$CONFIGURATION\" = \"Staging\" ]; then\n echo \"Removing non-English localizations for Release or Staging build\"\n find \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\" -type d -name \"*.lproj\" ! -name \"en.lproj\" -exec rm -r {} +\nfi\n\n# Ensure the output directory exists\nmkdir -p \"${DERIVED_FILE_DIR}\"\n\n# Final output\necho \">> Creating output flag file at: ${DERIVED_FILE_DIR}/localization-cleanup-done.flag\"\ntouch \"${DERIVED_FILE_DIR}/localization-cleanup-done.flag\"\n";
};
/* End PBXShellScriptBuildPhase section */
diff --git a/ios/MullvadVPN/Coordinators/AccountCoordinator.swift b/ios/MullvadVPN/Coordinators/AccountCoordinator.swift
index 228ba731f5..d3756aaf11 100644
--- a/ios/MullvadVPN/Coordinators/AccountCoordinator.swift
+++ b/ios/MullvadVPN/Coordinators/AccountCoordinator.swift
@@ -137,37 +137,18 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked
devicesProxy: interactor.deviceProxy
),
style: .deviceManagement,
- onError: { title, error in
- let errorDescription = if case let .network(urlError) = error as? REST.Error {
- urlError.localizedDescription
- } else {
- error.localizedDescription
- }
- let presentation = AlertPresentation(
- id: "device-management-error-alert",
+ onError: { [weak self] title, error in
+ self?.presentError(
+ "device-management-error-alert",
title: title,
- message: errorDescription,
- buttons: [
- AlertAction(
- title: NSLocalizedString(
- "ERROR_ALERT_OK_ACTION",
- tableName: "DeviceManagement",
- value: "Got it!",
- comment: ""
- ),
- style: .default
- ),
- ]
+ message: error.localizedDescription
)
-
- let presenter = AlertPresenter(context: self)
- presenter.showAlert(presentation: presentation, animated: true)
}
)
)
controller.title = NSLocalizedString(
"MANAGE_DEVICES_TITLE",
- tableName: "Manage devices",
+ tableName: "DeviceManagement",
value: "Manage devices",
comment: ""
)
@@ -178,16 +159,32 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting, @unchecked
})
)
controller.navigationItem.rightBarButtonItem = doneButton
- let subNavigationController = CustomNavigationController(
- rootViewController: controller
- )
+ let subNavigationController = CustomNavigationController(rootViewController: controller)
subNavigationController.navigationItem.largeTitleDisplayMode = .always
subNavigationController.navigationBar.prefersLargeTitles = true
- navigationController
- .present(
- subNavigationController,
- animated: true
- )
+ navigationController.present(subNavigationController, animated: true)
+ }
+
+ private func presentError(_ id: String, title: String, message: String) {
+ let presentation = AlertPresentation(
+ id: id,
+ title: title,
+ message: message,
+ buttons: [
+ AlertAction(
+ title: NSLocalizedString(
+ "ERROR_ALERT_OK_ACTION",
+ tableName: "Common",
+ value: "Got it!",
+ comment: ""
+ ),
+ style: .default
+ ),
+ ]
+ )
+
+ let presenter = AlertPresenter(context: self)
+ presenter.showAlert(presentation: presentation, animated: true)
}
@MainActor
diff --git a/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift b/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift
index 45eee26860..e1ac172e93 100644
--- a/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift
+++ b/ios/MullvadVPN/Coordinators/CustomLists/EditLocationsCoordinator.swift
@@ -13,7 +13,7 @@ import Routing
import UIKit
@MainActor
-class EditLocationsCoordinator: Coordinator, Presentable, Presenting, Sendable {
+class EditLocationsCoordinator: Coordinator, Presentable, Presenting {
private let navigationController: UINavigationController
private let nodes: [LocationNode]
private var subject: CurrentValueSubject<CustomListViewModel, Never>
diff --git a/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift
index 898a518411..b7435b0656 100644
--- a/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift
@@ -44,7 +44,6 @@ enum SettingsNavigationRoute: Equatable {
}
/// Top-level settings coordinator.
-@MainActor
final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsViewControllerDelegate,
UINavigationControllerDelegate, Sendable {
private let logger = Logger(label: "SettingsNavigationCoordinator")
diff --git a/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift
index c7fff5b197..137303b67c 100644
--- a/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift
+++ b/ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift
@@ -138,15 +138,28 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver, @unchec
func addPayment(_ payment: SKPayment, for accountNumber: String) {
logger.debug("Validating account before the purchase.")
+ let productIdentifier = payment.productIdentifier
+ let quantity = payment.quantity
+ let requestData = payment.requestData
+ let applicationUsername = payment.applicationUsername
+ let simulatesAskToBuyInSandbox = payment.simulatesAskToBuyInSandbox
+
// Validate account token before adding new payment to the queue.
validateAccount(accountNumber: accountNumber) { error in
+ // Reconstruct a new SKMutablePayment with the same fields
+ let cloned = SKMutablePayment()
+ cloned.productIdentifier = productIdentifier
+ cloned.quantity = quantity
+ cloned.requestData = requestData
+ cloned.applicationUsername = applicationUsername
+ cloned.simulatesAskToBuyInSandbox = simulatesAskToBuyInSandbox
+
if let error {
self.logger.error("Failed to validate the account. Payment is ignored.")
-
let event = StorePaymentEvent.failure(
StorePaymentFailure(
transaction: nil,
- payment: payment,
+ payment: cloned,
accountNumber: accountNumber,
error: error
)
@@ -158,8 +171,8 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver, @unchec
} else {
self.logger.debug("Add payment to the queue.")
- self.associateAccountNumber(accountNumber, and: payment)
- self.paymentQueue.add(payment)
+ self.associateAccountNumber(accountNumber, and: cloned)
+ self.paymentQueue.add(cloned)
}
}
}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift b/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift
index 1e76a42e9f..39831b9464 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift
@@ -14,7 +14,7 @@ protocol SettingsCellEventHandler {
}
@MainActor
-final class SettingsCellFactory: @preconcurrency CellFactoryProtocol, Sendable {
+final class SettingsCellFactory: @preconcurrency CellFactoryProtocol {
let tableView: UITableView
var delegate: SettingsCellEventHandler?
var viewModel: SettingsViewModel
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift b/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift
index 783cac1ee1..9348e198aa 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift
@@ -11,7 +11,7 @@ import MullvadSettings
import Routing
import UIKit
-protocol SettingsViewControllerDelegate: AnyObject, Sendable {
+protocol SettingsViewControllerDelegate: AnyObject {
func settingsViewControllerDidFinish(_ controller: SettingsViewController)
func settingsViewController(
_ controller: SettingsViewController,
diff --git a/ios/MullvadVPN/Views/MullvadAlert.swift b/ios/MullvadVPN/Views/MullvadAlert.swift
index 7f97861122..bad2b8a08e 100644
--- a/ios/MullvadVPN/Views/MullvadAlert.swift
+++ b/ios/MullvadVPN/Views/MullvadAlert.swift
@@ -31,57 +31,85 @@ struct AlertModifier: ViewModifier {
func body(content: Content) -> some View {
content
.fullScreenCover(item: $alert) { alert in
- VStack {
- Spacer()
- VStack(spacing: 16) {
- switch alert.type {
- case .error, .warning:
- Image.mullvadIconAlert
- .resizable()
- .frame(width: 48, height: 48)
- }
- HStack {
- Text(alert.message)
- .font(.mullvadSmall)
- .foregroundColor(.mullvadTextPrimary.opacity(0.6))
- Spacer()
- }
- VStack(spacing: 16) {
- if let action = alert.action {
- MainButton(
- text: action.title,
- style: action.type,
- action: {
- Task {
- loading = true
- await action.handler()
- loading = false
- }
- }
- )
- .accessibilityIdentifier(action.identifier)
- }
- MainButton(
- text: alert.dismissButtonTitle,
- style: .default,
- action: { self.alert = nil }
- )
- }
- }
- .padding()
- .background(Color.mullvadBackground)
- .cornerRadius(8)
- Spacer()
- }
- .accessibilityElement(children: .contain)
- .accessibilityIdentifier(.alertContainerView)
- .padding()
- .background(ClearBackgroundView())
+ alertView(for: alert)
}
.transaction {
$0.disablesAnimations = true
}
}
+
+ @ViewBuilder
+ private func alertView(for alert: MullvadAlert) -> some View {
+ VStack {
+ Spacer()
+ alertContent(for: alert)
+ Spacer()
+ }
+ .accessibilityElement(children: .contain)
+ .accessibilityIdentifier(.alertContainerView)
+ .padding()
+ .background(ClearBackgroundView())
+ }
+
+ @ViewBuilder
+ private func alertContent(for alert: MullvadAlert) -> some View {
+ VStack(spacing: 16) {
+ alertIcon(for: alert.type)
+ alertMessage(alert.message)
+ VStack(spacing: 16) {
+ alertAction(for: alert.action)
+ alertAction(for: MullvadAlert.Action(
+ type: .default,
+ title: alert.dismissButtonTitle,
+ identifier: nil,
+ handler: { self.alert = nil }
+ ))
+ }
+ }
+ .padding()
+ .background(Color.mullvadBackground)
+ .cornerRadius(8)
+ }
+
+ @ViewBuilder
+ private func alertIcon(for type: MullvadAlert.AlertType) -> some View {
+ switch type {
+ case .error, .warning:
+ Image.mullvadIconAlert
+ .resizable()
+ .frame(width: 48, height: 48)
+ }
+ }
+
+ @ViewBuilder
+ private func alertMessage(_ message: LocalizedStringKey) -> some View {
+ HStack {
+ Text(message)
+ .font(.mullvadSmall)
+ .foregroundColor(.mullvadTextPrimary.opacity(0.6))
+ Spacer()
+ }
+ }
+
+ @ViewBuilder
+ private func alertAction(for action: MullvadAlert.Action?) -> some View {
+ if let action = action {
+ MainButton(
+ text: action.title,
+ style: action.type,
+ action: {
+ Task {
+ loading = true
+ await action.handler()
+ loading = false
+ }
+ }
+ )
+ .accessibilityIdentifier(action.identifier)
+ } else {
+ EmptyView()
+ }
+ }
}
extension View {
diff --git a/ios/MullvadVPN/Views/SpinnerActivityIndicatorView.swift b/ios/MullvadVPN/Views/SpinnerActivityIndicatorView.swift
index 2098a06b97..555411bea9 100644
--- a/ios/MullvadVPN/Views/SpinnerActivityIndicatorView.swift
+++ b/ios/MullvadVPN/Views/SpinnerActivityIndicatorView.swift
@@ -14,7 +14,7 @@ class SpinnerActivityIndicatorView: UIView {
private static let animationDuration = 0.6
@MainActor
- enum Style: Sendable {
+ enum Style {
case small, medium, large, custom
var intrinsicSize: CGSize {
diff --git a/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift b/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift
index a86bebbd54..8d04e5d4f6 100644
--- a/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift
+++ b/ios/PacketTunnel/PacketTunnelProvider/NEProviderStopReason+Debug.swift
@@ -9,9 +9,11 @@
import Foundation
import NetworkExtension
-extension NEProviderStopReason: CustomStringConvertible {
+struct ProviderStopReasonWrapper: CustomStringConvertible {
+ let reason: NEProviderStopReason
+
public var description: String {
- switch self {
+ switch reason {
case .none:
return "none"
case .userInitiated:
@@ -49,7 +51,7 @@ extension NEProviderStopReason: CustomStringConvertible {
case .internalError:
return "internal error"
@unknown default:
- return "unknown value (\(rawValue))"
+ return "unknown value (\(reason.rawValue))"
}
}
}
diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift
index 68b09095a8..e949a36709 100644
--- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift
+++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift
@@ -180,7 +180,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
}
override func stopTunnel(with reason: NEProviderStopReason) async {
- providerLogger.debug("stopTunnel: \(reason)")
+ providerLogger.debug("stopTunnel: \(ProviderStopReasonWrapper(reason: reason))")
stopObservingActorState()
diff --git a/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapterError+Localization.swift b/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapterError+Localization.swift
index fce388c9a0..89d4312fd9 100644
--- a/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapterError+Localization.swift
+++ b/ios/PacketTunnel/WireGuardAdapter/WireGuardAdapterError+Localization.swift
@@ -9,9 +9,11 @@
import Foundation
import WireGuardKit
-extension WireGuardAdapterError: LocalizedError {
+struct WireGuardAdapterErrorWrapper: LocalizedError {
+ let error: WireGuardAdapterError
+
public var errorDescription: String? {
- switch self {
+ switch error {
case .cannotLocateTunnelFileDescriptor:
return "Failure to locate tunnel file descriptor."
diff --git a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
index 7cd230e2fb..f1deb3f40b 100644
--- a/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
+++ b/ios/PacketTunnelCore/Actor/PacketTunnelActor.swift
@@ -85,21 +85,23 @@ public actor PacketTunnelActor {
*/
private nonisolated func consumeEvents(channel: EventChannel) {
Task.detached { [weak self] in
+ guard let self else { return }
for await event in channel {
- guard let self else { return }
+ await self.handleEvent(event)
+ }
+ }
+ }
- self.logger.debug("Received event: \(event.logFormat())")
+ private func handleEvent(_ event: Event) async {
+ self.logger.debug("Received event: \(event.logFormat())")
- let effects = await self.runReducer(event)
+ let effects = self.runReducer(event)
- for effect in effects {
- await executeEffect(effect)
- }
- }
+ for effect in effects {
+ await executeEffect(effect)
}
}
- // swiftlint:disable:next function_body_length
func executeEffect(_ effect: Effect) async {
switch effect {
case .startDefaultPathObserver:
@@ -113,46 +115,65 @@ public actor PacketTunnelActor {
case let .updateTunnelMonitorPath(networkPath):
handleDefaultPathChange(networkPath)
case let .startConnection(nextRelays):
- do {
- try await tryStart(nextRelays: nextRelays)
- } catch {
- logger.error(error: error, message: "Failed to start the tunnel.")
- await setErrorStateInternal(with: error)
- }
+ await handleStartConnection(nextRelays: nextRelays)
case let .restartConnection(nextRelays, reason):
- do {
- try await tryStart(nextRelays: nextRelays, reason: reason)
- } catch {
- logger.error(error: error, message: "Failed to reconnect the tunnel.")
- await setErrorStateInternal(with: error)
- }
+ await handleRestartConnection(nextRelays: nextRelays, reason: reason)
case let .reconnect(nextRelay):
eventChannel.send(.reconnect(nextRelay))
case .stopTunnelAdapter:
- do {
- try await tunnelAdapter.stop()
- } catch {
- logger.error(error: error, message: "Failed to stop adapter.")
- }
- state = .disconnected
+ await handleStopTunnelAdapter()
case let .configureForErrorState(reason):
await setErrorStateInternal(with: reason)
case let .cacheActiveKey(lastKeyRotation):
cacheActiveKey(lastKeyRotation: lastKeyRotation)
case let .reconfigureForEphemeralPeer(configuration, configurationSemaphore):
- do {
- try await updateEphemeralPeerNegotiationState(configuration: configuration)
- } catch {
- logger.error(error: error, message: "Failed to reconfigure tunnel after each hop negotiation.")
- await setErrorStateInternal(with: error)
- }
- configurationSemaphore.send()
+ await handleReconfigureForEphemeralPeer(configuration: configuration, semaphore: configurationSemaphore)
case .connectWithEphemeralPeer:
await connectWithEphemeralPeer()
case .setDisconnectedState:
self.state = .disconnected
}
}
+
+ private func handleStartConnection(nextRelays: NextRelays) async {
+ do {
+ try await tryStart(nextRelays: nextRelays)
+ } catch {
+ logger.error(error: error, message: "Failed to start the tunnel.")
+ await setErrorStateInternal(with: error)
+ }
+ }
+
+ private func handleRestartConnection(nextRelays: NextRelays, reason: ActorReconnectReason) async {
+ do {
+ try await tryStart(nextRelays: nextRelays, reason: reason)
+ } catch {
+ logger.error(error: error, message: "Failed to reconnect the tunnel.")
+ await setErrorStateInternal(with: error)
+ }
+ }
+
+ private func handleStopTunnelAdapter() async {
+ do {
+ try await tunnelAdapter.stop()
+ } catch {
+ logger.error(error: error, message: "Failed to stop adapter.")
+ }
+ state = .disconnected
+ }
+
+ private func handleReconfigureForEphemeralPeer(
+ configuration: EphemeralPeerNegotiationState,
+ semaphore: OneshotChannel
+ ) async {
+ do {
+ try await updateEphemeralPeerNegotiationState(configuration: configuration)
+ } catch {
+ logger.error(error: error, message: "Failed to reconfigure tunnel after each hop negotiation.")
+ await setErrorStateInternal(with: error)
+ }
+ semaphore.send()
+ }
}
// MARK: -
diff --git a/ios/Routing/Coordinator.swift b/ios/Routing/Coordinator.swift
index dd951329c0..bbe8c0ae9b 100644
--- a/ios/Routing/Coordinator.swift
+++ b/ios/Routing/Coordinator.swift
@@ -16,7 +16,7 @@ import UIKit
more manageable and reusable.
*/
@MainActor
-open class Coordinator: NSObject, Sendable {
+open class Coordinator: NSObject {
/// Private trace log.
private lazy var logger = Logger(label: "\(Self.self)")
diff --git a/ios/Routing/Router/ApplicationRouter.swift b/ios/Routing/Router/ApplicationRouter.swift
index 0dde76f426..6fb49325d6 100644
--- a/ios/Routing/Router/ApplicationRouter.swift
+++ b/ios/Routing/Router/ApplicationRouter.swift
@@ -14,7 +14,7 @@ import UIKit
Main application router.
*/
@MainActor
-public final class ApplicationRouter<RouteType: AppRouteProtocol>: Sendable {
+public final class ApplicationRouter<RouteType: AppRouteProtocol> {
nonisolated(unsafe) private let logger = Logger(label: "ApplicationRouter")
private(set) var modalStack: [RouteType.RouteGroupType] = []