diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift index 0c70c1a..b41cdbb 100644 --- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift +++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift @@ -5,6 +5,13 @@ struct VPNMenu: View { @EnvironmentObject var session: S @Environment(\.openSettings) private var openSettings + // There appears to be a race between the VPN service reporting itself as disconnected, + // and the system extension process exiting. When the VPN is toggled off and on quickly, + // an error is shown: "The VPN session failed because an internal error occurred". + // This forces the user to wait a few seconds before they can toggle the VPN back on. + @State private var waitCleanup = false + private var waitCleanupDuration: Duration = .seconds(6) + let inspection = Inspection() var body: some View { @@ -16,7 +23,7 @@ struct VPNMenu: View { Toggle(isOn: Binding( get: { vpn.state == .connected || vpn.state == .connecting }, set: { isOn in Task { - if isOn { await vpn.start() } else { await vpn.stop() } + if isOn { await vpn.start() } else { await stop() } } } )) { @@ -86,11 +93,21 @@ struct VPNMenu: View { } private var vpnDisabled: Bool { - !session.hasSession || + waitCleanup || + !session.hasSession || vpn.state == .connecting || vpn.state == .disconnecting || vpn.state == .failed(.systemExtensionError(.needsUserApproval)) } + + private func stop() async { + await vpn.stop() + waitCleanup = true + Task { + try? await Task.sleep(for: waitCleanupDuration) + waitCleanup = false + } + } } func openSystemExtensionSettings() {