Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit060d932

Browse files
committed
chore: handle waking from device sleep
1 parent7d5b6c7 commit060d932

File tree

5 files changed

+37
-31
lines changed

5 files changed

+37
-31
lines changed

‎Coder Desktop/Coder Desktop/Views/VPNMenu.swift

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ struct VPNMenu<VPN: VPNService>: View {
55
@EnvironmentObjectvarstate:AppState
66
@Environment(\.openSettings)privatevaropenSettings
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-
@StateprivatevarwaitCleanup=false
13-
privatevarwaitCleanupDuration:Duration=.seconds(6)
14-
158
letinspection=Inspection<Self>()
169

1710
varbody:someView{
@@ -23,7 +16,7 @@ struct VPNMenu<VPN: VPNService>: View {
2316
Toggle(isOn:Binding(
2417
get:{ vpn.state==.connected || vpn.state==.connecting},
2518
set:{ isOninTask{
26-
if isOn{await vpn.start()}else{awaitstop()}
19+
if isOn{await vpn.start()}else{awaitvpn.stop()}
2720
}
2821
}
2922
)){
@@ -93,21 +86,11 @@ struct VPNMenu<VPN: VPNService>: View {
9386
}
9487

9588
privatevarvpnDisabled:Bool{
96-
waitCleanup ||
97-
!state.hasSession ||
89+
!session.hasSession ||
9890
vpn.state==.connecting ||
9991
vpn.state==.disconnecting ||
10092
vpn.state==.failed(.systemExtensionError(.needsUserApproval))
10193
}
102-
103-
privatefunc stop()async{
104-
await vpn.stop()
105-
waitCleanup=true
106-
Task{
107-
try?awaitTask.sleep(for: waitCleanupDuration)
108-
waitCleanup=false
109-
}
110-
}
11194
}
11295

11396
func openSystemExtensionSettings(){

‎Coder Desktop/VPN/Manager.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ actor Manager {
2727
fatalError("unknown architecture")
2828
#endif
2929
do{
30-
tryawaitdownload(src: dylibPath, dest: dest)
30+
letsessionConfig=URLSessionConfiguration.default
31+
// The tunnel might be asked to start before the network interfaces have woken up from sleep
32+
sessionConfig.waitsForConnectivity=true
33+
tryawaitdownload(src: dylibPath, dest: dest, urlSession:URLSession(configuration: sessionConfig))
3134
}catch{
3235
throw.download(error)
3336
}

‎Coder Desktop/VPN/PacketTunnelProvider.swift

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
4848
options _:[String:NSObject]?, completionHandler:@escaping(Error?)->Void
4949
){
5050
logger.info("startTunnel called")
51+
start(completionHandler)
52+
}
53+
54+
// called by `startTunnel` and on `wake`
55+
func start(_ completionHandler:@escaping(Error?)->Void){
5156
guard manager==nilelse{
5257
logger.error("startTunnel called with non-nil Manager")
5358
completionHandler(makeNSError(suffix:"PTP", desc:"Already running"))
@@ -99,8 +104,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
99104
with _:NEProviderStopReason, completionHandler:@escaping()->Void
100105
){
101106
logger.debug("stopTunnel called")
107+
teardown(completionHandler)
108+
}
109+
110+
// called by `stopTunnel` and `sleep`
111+
func teardown(_ completionHandler:@escaping()->Void){
102112
guardlet managerelse{
103-
logger.error("stopTunnel called with nil Manager")
113+
logger.error("teardown called with nil Manager")
104114
completionHandler()
105115
return
106116
}
@@ -125,15 +135,25 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
125135
}
126136
}
127137

138+
// sleep and wake reference: https://developer.apple.com/forums/thread/95988
128139
overridefunc sleep(completionHandler:@escaping()->Void){
129-
// Add code here to get ready to sleep.
130140
logger.debug("sleep called")
131-
completionHandler()
141+
teardown(completionHandler)
132142
}
133143

134144
overridefunc wake(){
135-
// Add code here to wake up.
136145
logger.debug("wake called")
146+
reasserting=true
147+
currentSettings=.init(tunnelRemoteAddress:"127.0.0.1")
148+
setTunnelNetworkSettings(nil)
149+
start{ errorin
150+
iflet error{
151+
self.logger.error("error starting tunnel after wake:\(error.localizedDescription)")
152+
self.cancelTunnelWithError(error)
153+
}else{
154+
self.reasserting=false
155+
}
156+
}
137157
}
138158

139159
// Wrapper around `setTunnelNetworkSettings` that supports merging updates

‎Coder Desktop/VPNLib/Download.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public class SignatureValidator {
101101
}
102102
}
103103

104-
publicfunc download(src:URL, dest:URL)asyncthrows(DownloadError){
104+
publicfunc download(src:URL, dest:URL, urlSession:URLSession)asyncthrows(DownloadError){
105105
varreq=URLRequest(url: src)
106106
ifFileManager.default.fileExists(atPath: dest.path){
107107
iflet existingFileData=try?Data(contentsOf: dest, options:.mappedIfSafe){
@@ -112,7 +112,7 @@ public func download(src: URL, dest: URL) async throws(DownloadError) {
112112
lettempURL:URL
113113
letresponse:URLResponse
114114
do{
115-
(tempURL, response)=tryawaitURLSession.shared.download(for: req)
115+
(tempURL, response)=tryawaiturlSession.download(for: req)
116116
}catch{
117117
throw.networkError(error)
118118
}

‎Coder Desktop/VPNLibTests/DownloadTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct DownloadTests {
1313
letfileURL=URL(string:"http://example.com/test1.txt")!
1414
Mock(url: fileURL, contentType:.html, statusCode:200, data:[.get: testData]).register()
1515

16-
tryawaitdownload(src: fileURL, dest: destinationURL)
16+
tryawaitdownload(src: fileURL, dest: destinationURL, urlSession:URLSession.shared)
1717

1818
try #require(FileManager.default.fileExists(atPath: destinationURL.path))
1919
defer{try?FileManager.default.removeItem(at: destinationURL)}
@@ -32,7 +32,7 @@ struct DownloadTests {
3232

3333
Mock(url: fileURL, contentType:.html, statusCode:200, data:[.get: testData]).register()
3434

35-
tryawaitdownload(src: fileURL, dest: destinationURL)
35+
tryawaitdownload(src: fileURL, dest: destinationURL, urlSession:URLSession.shared)
3636
try #require(FileManager.default.fileExists(atPath: destinationURL.path))
3737
letdownloadedData=tryData(contentsOf: destinationURL)
3838
#expect(downloadedData== testData)
@@ -44,7 +44,7 @@ struct DownloadTests {
4444
}
4545
mock.register()
4646

47-
tryawaitdownload(src: fileURL, dest: destinationURL)
47+
tryawaitdownload(src: fileURL, dest: destinationURL, urlSession:URLSession.shared)
4848
letunchangedData=tryData(contentsOf: destinationURL)
4949
#expect(unchangedData== testData)
5050
#expect(etagIncluded)
@@ -61,7 +61,7 @@ struct DownloadTests {
6161

6262
Mock(url: fileURL, contentType:.html, statusCode:200, data:[.get: ogData]).register()
6363

64-
tryawaitdownload(src: fileURL, dest: destinationURL)
64+
tryawaitdownload(src: fileURL, dest: destinationURL, urlSession:URLSession.shared)
6565
try #require(FileManager.default.fileExists(atPath: destinationURL.path))
6666
vardownloadedData=tryData(contentsOf: destinationURL)
6767
#expect(downloadedData== ogData)
@@ -73,7 +73,7 @@ struct DownloadTests {
7373
}
7474
mock.register()
7575

76-
tryawaitdownload(src: fileURL, dest: destinationURL)
76+
tryawaitdownload(src: fileURL, dest: destinationURL, urlSession:URLSession.shared)
7777
downloadedData=tryData(contentsOf: destinationURL)
7878
#expect(downloadedData== newData)
7979
#expect(etagIncluded)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp