@@ -5,6 +5,13 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
55 @EnvironmentObject var session : S
66 @Environment ( \. openSettings) private var openSettings
77
8+ // There appears to be a race between the VPN service reporting itself as disconnected,
9+ // and the system extension process exiting. When the VPN is toggled off and on quickly,
10+ // an error is shown: "The VPN session failed because an internal error occurred".
11+ // This forces the user to wait a few seconds before they can toggle the VPN back on.
12+ @State private var waitCleanup = false
13+ private var waitCleanupDuration : Duration = . seconds( 6 )
14+
815 let inspection = Inspection < Self > ( )
916
1017 var body : some View {
@@ -16,7 +23,7 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
1623 Toggle ( isOn: Binding (
1724 get: { vpn. state == . connected || vpn. state == . connecting } ,
1825 set: { isOn in Task {
19- if isOn { await vpn. start ( ) } else { await vpn . stop ( ) }
26+ if isOn { await vpn. start ( ) } else { await stop ( ) }
2027 }
2128 }
2229 ) ) {
@@ -86,11 +93,21 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
8693 }
8794
8895 private var vpnDisabled : Bool {
89- !session. hasSession ||
96+ waitCleanup ||
97+ !session. hasSession ||
9098 vpn. state == . connecting ||
9199 vpn. state == . disconnecting ||
92100 vpn. state == . failed( . systemExtensionError( . needsUserApproval) )
93101 }
102+
103+ private func stop( ) async {
104+ await vpn. stop ( )
105+ waitCleanup = true
106+ Task {
107+ try ? await Task . sleep ( for: waitCleanupDuration)
108+ waitCleanup = false
109+ }
110+ }
94111}
95112
96113func openSystemExtensionSettings( ) {
0 commit comments