mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 18:18:55 +00:00
feat(apple): Poll tunnel for new configuration every 1s (#9083)
Similar to how we fetch new resources, we add a Configuration poller that fetches new configuration every 1s. If the configuration is unchanged, we respond to the caller with a cached copy to avoid needing to serialize the data over IPC. Related: #4505
This commit is contained in:
@@ -14,6 +14,8 @@ import AppKit
|
||||
#endif
|
||||
|
||||
@MainActor
|
||||
// TODO: Move some state logic to view models
|
||||
// swiftlint:disable:next type_body_length
|
||||
public final class Store: ObservableObject {
|
||||
@Published private(set) var favorites = Favorites()
|
||||
@Published private(set) var resourceList: ResourceList = .loading
|
||||
@@ -36,6 +38,8 @@ public final class Store: ObservableObject {
|
||||
|
||||
let sessionNotification = SessionNotification()
|
||||
|
||||
private var configurationTimer: Timer?
|
||||
private var configurationUpdateTask: Task<Void, Never>?
|
||||
private var resourcesTimer: Timer?
|
||||
private var resourceUpdateTask: Task<Void, Never>?
|
||||
|
||||
@@ -105,6 +109,14 @@ public final class Store: ObservableObject {
|
||||
func handleStatusChange(newStatus: NEVPNStatus) async throws {
|
||||
status = newStatus
|
||||
|
||||
if status == .invalid {
|
||||
// VPN configuration was yanked from system settings
|
||||
endConfigurationPolling()
|
||||
} else {
|
||||
// This is a no-op if the timer is already active
|
||||
beginConfigurationPolling()
|
||||
}
|
||||
|
||||
if status == .connected {
|
||||
beginUpdatingResources()
|
||||
} else {
|
||||
@@ -273,6 +285,43 @@ public final class Store: ObservableObject {
|
||||
try ipcClient().start(token: token)
|
||||
}
|
||||
|
||||
private func beginConfigurationPolling() {
|
||||
// Ensure we're idempotent if called twice
|
||||
if self.configurationTimer != nil {
|
||||
return
|
||||
}
|
||||
|
||||
let updateConfiguration: @Sendable (Timer) -> Void = { _ in
|
||||
Task {
|
||||
await MainActor.run {
|
||||
self.configurationUpdateTask?.cancel()
|
||||
self.configurationUpdateTask = Task {
|
||||
if !Task.isCancelled {
|
||||
do {
|
||||
self.configuration = try await self.ipcClient().getConfiguration()
|
||||
} catch {
|
||||
Log.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let intervalInSeconds: TimeInterval = 1
|
||||
let timer = Timer(timeInterval: intervalInSeconds, repeats: true, block: updateConfiguration)
|
||||
|
||||
RunLoop.main.add(timer, forMode: .common)
|
||||
self.configurationTimer = timer
|
||||
}
|
||||
|
||||
private func endConfigurationPolling() {
|
||||
configurationUpdateTask?.cancel()
|
||||
configurationTimer?.invalidate()
|
||||
configurationTimer = nil
|
||||
self.configuration = nil
|
||||
}
|
||||
|
||||
// Network Extensions don't have a 2-way binding up to the GUI process,
|
||||
// so we need to periodically ask the tunnel process for them.
|
||||
private func beginUpdatingResources() {
|
||||
|
||||
Reference in New Issue
Block a user