@@ -5,6 +5,13 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
5
5
@EnvironmentObject var session : S
6
6
@Environment ( \. openSettings) private var openSettings
7
7
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
+
8
15
let inspection = Inspection < Self > ( )
9
16
10
17
var body : some View {
@@ -16,7 +23,7 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
16
23
Toggle ( isOn: Binding (
17
24
get: { vpn. state == . connected || vpn. state == . connecting } ,
18
25
set: { isOn in Task {
19
- if isOn { await vpn. start ( ) } else { await vpn . stop ( ) }
26
+ if isOn { await vpn. start ( ) } else { await stop ( ) }
20
27
}
21
28
}
22
29
) ) {
@@ -86,11 +93,21 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
86
93
}
87
94
88
95
private var vpnDisabled : Bool {
89
- !session. hasSession ||
96
+ waitCleanup ||
97
+ !session. hasSession ||
90
98
vpn. state == . connecting ||
91
99
vpn. state == . disconnecting ||
92
100
vpn. state == . failed( . systemExtensionError( . needsUserApproval) )
93
101
}
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
+ }
94
111
}
95
112
96
113
func openSystemExtensionSettings( ) {
0 commit comments