mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
fix(apple): Use Task.detached when loading sysex and vpn config (#7815)
When the app starts, we perform various checks in the `AppViewModel.init` which read and write to disk, which can potentially be slow (a few seconds), especially for busy rotational hard drives. These were performed inside a regular `Task` closure, but since AppViewModel is annotated `@MainActor`, that meant this Task blocked the main UI thread until the operations completed. In practice this wasn't an issue because it simply manifested as the app taking a couple seconds to launch under these conditions. We fix this by simply using a `Task.detached` which will run the operations on another thread. Now, the first window will pop up sooner and immediately show the `ProgressView()` (i.e. a loading spinner icon) until these operations complete. A few minor reorganizing of the `os()` macro was also performed because some of the variables now need to be `await`ed because they live on the main thread. refs #7798
This commit is contained in:
@@ -115,11 +115,11 @@ public final class Store: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func checkedIfInstalled() async throws {
|
||||
#if os(macOS)
|
||||
func checkedSystemExtensionStatus() async throws -> SystemExtensionStatus {
|
||||
let checker = SystemExtensionManager()
|
||||
|
||||
self.systemExtensionStatus = try await withCheckedThrowingContinuation {
|
||||
let status = try await withCheckedThrowingContinuation {
|
||||
(continuation: CheckedContinuation<SystemExtensionStatus, Error>) in
|
||||
|
||||
checker.checkStatus(
|
||||
@@ -130,14 +130,16 @@ public final class Store: ObservableObject {
|
||||
|
||||
// If already installed but the wrong version, go ahead and install.
|
||||
// This shouldn't prompt the user.
|
||||
if self.systemExtensionStatus == .needsReplacement {
|
||||
if status == .needsReplacement {
|
||||
try await installSystemExtension()
|
||||
}
|
||||
#endif
|
||||
|
||||
self.systemExtensionStatus = status
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func installSystemExtension() async throws {
|
||||
#if os(macOS)
|
||||
let installer = SystemExtensionManager()
|
||||
|
||||
// Apple recommends installing the system extension as early as possible after app launch.
|
||||
@@ -150,8 +152,8 @@ public final class Store: ObservableObject {
|
||||
continuation: continuation
|
||||
)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
func grantVPNPermission() async throws {
|
||||
// Create a new VPN configuration in system settings.
|
||||
|
||||
@@ -32,27 +32,30 @@ public class AppViewModel: ObservableObject {
|
||||
self.favorites = favorites
|
||||
self.store = store
|
||||
|
||||
Task {
|
||||
Task.detached { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
do {
|
||||
try await self.store.bindToVPNConfigurationUpdates()
|
||||
let vpnConfigurationStatus = await self.store.status
|
||||
|
||||
#if os(macOS)
|
||||
try await self.store.checkedIfInstalled()
|
||||
let isInstalled = self.store.systemExtensionStatus == .installed
|
||||
let systemExtensionStatus = try await self.store.checkedSystemExtensionStatus()
|
||||
|
||||
if !isInstalled || self.store.status == .invalid {
|
||||
if systemExtensionStatus != .installed
|
||||
|| vpnConfigurationStatus == .invalid {
|
||||
|
||||
// Show the main Window if VPN permission needs to be granted
|
||||
AppViewModel.WindowDefinition.main.openWindow()
|
||||
await AppViewModel.WindowDefinition.main.openWindow()
|
||||
} else {
|
||||
AppViewModel.WindowDefinition.main.window()?.close()
|
||||
await AppViewModel.WindowDefinition.main.window()?.close()
|
||||
}
|
||||
#endif
|
||||
|
||||
if self.store.status == .disconnected {
|
||||
if vpnConfigurationStatus == .disconnected {
|
||||
|
||||
// Try to connect on start
|
||||
self.store.vpnConfigurationManager.start()
|
||||
await self.store.vpnConfigurationManager.start()
|
||||
}
|
||||
} catch {
|
||||
Log.error(error)
|
||||
|
||||
@@ -27,21 +27,23 @@ final class GrantVPNViewModel: ObservableObject {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
func installSystemExtensionButtonTapped() {
|
||||
Task {
|
||||
do {
|
||||
try await store.installSystemExtension()
|
||||
|
||||
#if os(macOS)
|
||||
|
||||
// The window has a tendency to go to the background after installing
|
||||
// the system extension
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
#endif
|
||||
|
||||
} catch {
|
||||
Log.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
func grantPermissionButtonTapped() {
|
||||
Log.log("\(#function)")
|
||||
|
||||
Reference in New Issue
Block a user