diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index abc98271..29a85ea2 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -1898,6 +1898,7 @@ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout catalyst"; SUPPORTS_MACCATALYST = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_STRICT_CONCURRENCY = targeted; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -1924,6 +1925,7 @@ PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout"; "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout catalyst"; SUPPORTS_MACCATALYST = YES; + SWIFT_STRICT_CONCURRENCY = targeted; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Passepartout/App/Context/AppContext+Shared.swift b/Passepartout/App/Context/AppContext+Shared.swift index a4543355..27fb8f82 100644 --- a/Passepartout/App/Context/AppContext+Shared.swift +++ b/Passepartout/App/Context/AppContext+Shared.swift @@ -53,8 +53,6 @@ extension ProfileManager { } extension ProviderManager { - - @MainActor static let shared = AppContext.shared.providerManager } diff --git a/Passepartout/App/Domain/IntentDispatcher.swift b/Passepartout/App/Domain/IntentDispatcher.swift index 7a819cd6..b470e859 100644 --- a/Passepartout/App/Domain/IntentDispatcher.swift +++ b/Passepartout/App/Domain/IntentDispatcher.swift @@ -27,6 +27,7 @@ import Foundation import Intents import PassepartoutLibrary +@MainActor final class IntentDispatcher { private struct Groups { static let vpn = "VPN" diff --git a/Passepartout/App/Extensions/ProviderProfileAvailability.swift b/Passepartout/App/Extensions/ProviderProfileAvailability.swift index 04e55bfc..88af7f4f 100644 --- a/Passepartout/App/Extensions/ProviderProfileAvailability.swift +++ b/Passepartout/App/Extensions/ProviderProfileAvailability.swift @@ -26,6 +26,7 @@ import Foundation import PassepartoutLibrary +@MainActor protocol ProviderProfileAvailability { var profile: Profile { get } diff --git a/Passepartout/App/Mac/MacBundleDelegate.swift b/Passepartout/App/Mac/MacBundleDelegate.swift index 0116784a..cb4bdc5d 100644 --- a/Passepartout/App/Mac/MacBundleDelegate.swift +++ b/Passepartout/App/Mac/MacBundleDelegate.swift @@ -43,6 +43,7 @@ final class MacBundleDelegate: MacMenuDelegate { DefaultLightVPNManager() } + @MainActor var utils: LightUtils { DefaultLightUtils() } diff --git a/Passepartout/App/Managers/IntentsManager.swift b/Passepartout/App/Managers/IntentsManager.swift index 478d6239..ec29d0b5 100644 --- a/Passepartout/App/Managers/IntentsManager.swift +++ b/Passepartout/App/Managers/IntentsManager.swift @@ -25,7 +25,7 @@ import Combine import Foundation -import Intents +@preconcurrency import Intents import IntentsUI import PassepartoutLibrary diff --git a/Passepartout/App/Managers/PersistenceManager.swift b/Passepartout/App/Managers/PersistenceManager.swift index 8db4ea82..e4d2786b 100644 --- a/Passepartout/App/Managers/PersistenceManager.swift +++ b/Passepartout/App/Managers/PersistenceManager.swift @@ -29,6 +29,7 @@ import CoreData import Foundation import PassepartoutLibrary +@MainActor final class PersistenceManager: ObservableObject { let store: KeyValueStore @@ -80,16 +81,12 @@ final class PersistenceManager: ObservableObject { extension PersistenceManager { func eraseCloudKitStore() async { - await MainActor.run { - isErasingCloudKitStore = true - } + isErasingCloudKitStore = true await Self.eraseCloudKitStore( fromContainerWithId: ckContainerId, zoneId: .init(zoneName: ckCoreDataZone) ) - await MainActor.run { - isErasingCloudKitStore = false - } + isErasingCloudKitStore = false } // WARNING: this is not running on main actor diff --git a/Passepartout/App/Views/AddProviderViewModel.swift b/Passepartout/App/Views/AddProviderViewModel.swift index 2f45636c..7129be17 100644 --- a/Passepartout/App/Views/AddProviderViewModel.swift +++ b/Passepartout/App/Views/AddProviderViewModel.swift @@ -27,6 +27,8 @@ import Foundation import PassepartoutLibrary extension AddProviderView { + + @MainActor final class ViewModel: ObservableObject { enum PendingOperation { case index diff --git a/Passepartout/App/Views/EndpointView+OpenVPN.swift b/Passepartout/App/Views/EndpointView+OpenVPN.swift index 84f19ab6..9c7c63af 100644 --- a/Passepartout/App/Views/EndpointView+OpenVPN.swift +++ b/Passepartout/App/Views/EndpointView+OpenVPN.swift @@ -329,6 +329,8 @@ private struct EndpointsByAddress: Identifiable { // MARK: - Bindings private extension ObservableProfile { + + @MainActor func builderBinding(providerManager: ProviderManager) -> Binding { .init { if self.value.isProvider { diff --git a/Passepartout/App/Views/EndpointView+WireGuard.swift b/Passepartout/App/Views/EndpointView+WireGuard.swift index 3cfe481d..e67f0f76 100644 --- a/Passepartout/App/Views/EndpointView+WireGuard.swift +++ b/Passepartout/App/Views/EndpointView+WireGuard.swift @@ -120,6 +120,8 @@ private extension EndpointView.WireGuardView { // MARK: - Bindings private extension ObservableProfile { + + @MainActor func builderBinding(providerManager: ProviderManager) -> Binding { .init { if self.value.isProvider { diff --git a/Passepartout/App/Views/ProfileView+Provider.swift b/Passepartout/App/Views/ProfileView+Provider.swift index 1ad39173..9a988a77 100644 --- a/Passepartout/App/Views/ProfileView+Provider.swift +++ b/Passepartout/App/Views/ProfileView+Provider.swift @@ -103,7 +103,9 @@ private extension ProfileView.ProviderSection { Label(L10n.Provider.Preset.title, systemImage: themeProviderPresetImage) .withTrailingText(currentProviderPreset) } - Button(action: refreshInfrastructure) { + Button { + refreshInfrastructure() + } label: { Text(L10n.Profile.Items.Provider.Refresh.caption) }.withTrailingProgress(when: isRefreshingInfrastructure) } footer: { diff --git a/Passepartout/App/Views/ProviderLocationView.swift b/Passepartout/App/Views/ProviderLocationView.swift index f4440c8b..2cfe072c 100644 --- a/Passepartout/App/Views/ProviderLocationView.swift +++ b/Passepartout/App/Views/ProviderLocationView.swift @@ -309,6 +309,8 @@ private extension ProviderLocationView.ServerListView { // MARK: - Bindings private extension ObservableProfile { + + @MainActor func selectedServerBinding(providerManager: ProviderManager, isPresented: Binding) -> Binding { .init { guard let serverId = self.value.providerServerId else { diff --git a/Passepartout/App/Views/ProviderPresetView.swift b/Passepartout/App/Views/ProviderPresetView.swift index 3d9b16b0..33ce37f4 100644 --- a/Passepartout/App/Views/ProviderPresetView.swift +++ b/Passepartout/App/Views/ProviderPresetView.swift @@ -95,6 +95,8 @@ private extension ProviderPresetView { // MARK: - Bindings private extension ObservableProfile { + + @MainActor func selectedPresetBinding(providerManager: ProviderManager) -> Binding { .init { guard let serverId = self.value.providerServerId else { diff --git a/PassepartoutLibrary/Sources/PassepartoutCore/Reusable/RateLimited.swift b/PassepartoutLibrary/Sources/PassepartoutCore/Reusable/RateLimited.swift index c5c1fa22..759e9b58 100644 --- a/PassepartoutLibrary/Sources/PassepartoutCore/Reusable/RateLimited.swift +++ b/PassepartoutLibrary/Sources/PassepartoutCore/Reusable/RateLimited.swift @@ -25,6 +25,7 @@ import Foundation +@MainActor public protocol RateLimited: AnyObject { associatedtype ActionID: Hashable diff --git a/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift index 6db4710c..950aea63 100644 --- a/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutProviders/Managers/ProviderManager.swift @@ -27,6 +27,7 @@ import Combine import Foundation import PassepartoutCore +@MainActor public final class ProviderManager: ObservableObject, RateLimited { private let localProvidersRepository: LocalProvidersRepository diff --git a/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Extensions/Profile+ProviderManager.swift b/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Extensions/Profile+ProviderManager.swift index 5d4a4518..ca2241d8 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Extensions/Profile+ProviderManager.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Extensions/Profile+ProviderManager.swift @@ -28,6 +28,7 @@ import PassepartoutCore import PassepartoutProviders import PassepartoutVPN +@MainActor extension Profile { public func providerServer(_ providerManager: ProviderManager) -> ProviderServer? { guard let serverId = providerServerId else { diff --git a/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Strategies/TunnelKitVPNManagerStrategy.swift b/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Strategies/TunnelKitVPNManagerStrategy.swift index 95b9b6b5..bdaf82f3 100644 --- a/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Strategies/TunnelKitVPNManagerStrategy.swift +++ b/PassepartoutLibrary/Sources/PassepartoutVPNImpl/Strategies/TunnelKitVPNManagerStrategy.swift @@ -133,7 +133,7 @@ extension TunnelKitVPNManagerStrategy { } public func reinstate(_ parameters: VPNConfigurationParameters) async throws { - let configuration = try vpnConfiguration(withParameters: parameters) + let configuration = try await vpnConfiguration(withParameters: parameters) guard let vpnType = configuration.neConfiguration as? VPNProtocolProviding else { fatalError("Configuration must implement VPNProtocolProviding") } @@ -154,7 +154,7 @@ extension TunnelKitVPNManagerStrategy { } public func connect(_ parameters: VPNConfigurationParameters) async throws { - let configuration = try vpnConfiguration(withParameters: parameters) + let configuration = try await vpnConfiguration(withParameters: parameters) guard let vpnType = configuration.neConfiguration as? VPNProtocolProviding else { fatalError("Configuration must implement VPNProtocolProviding") } @@ -301,6 +301,8 @@ private extension TunnelKitVPNManagerStrategy { // MARK: Configuration private extension TunnelKitVPNManagerStrategy { + + @MainActor func vpnConfiguration(withParameters parameters: VPNConfigurationParameters) throws -> TunnelKitVPNConfiguration { let profile = parameters.profile do { diff --git a/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift b/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift index b59484e9..35f47b85 100644 --- a/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift +++ b/PassepartoutLibrary/Tests/PassepartoutProvidersTests/ProvidersTests.swift @@ -30,6 +30,7 @@ import PassepartoutProviders @testable import PassepartoutProvidersImpl import XCTest +@MainActor final class ProvidersTests: XCTestCase { private var persistence: ProvidersPersistence!