@@ -6,16 +6,113 @@ actor Manager {
6
6
let ptp : PacketTunnelProvider
7
7
let downloader : Downloader
8
8
9
- var tunnelHandle : TunnelHandle ?
10
- var speaker : Speaker < Vpn_ManagerMessage , Vpn_TunnelMessage > ?
9
+ let tunnelHandle : TunnelHandle
10
+ let speaker : Speaker < Vpn_ManagerMessage , Vpn_TunnelMessage >
11
+ var readLoop : Task < Void , Error > !
11
12
// TODO: XPC Speaker
12
13
13
14
private let dest = FileManager . default. urls ( for: . documentDirectory, in: . userDomainMask)
14
15
. first!. appending ( path: " coder-vpn.dylib " )
15
16
private let logger = Logger ( subsystem: Bundle . main. bundleIdentifier!, category: " manager " )
16
17
17
- init ( with: PacketTunnelProvider ) {
18
+ init ( with: PacketTunnelProvider , server : URL ) async throws ( ManagerError ) {
18
19
ptp = with
19
20
downloader = Downloader ( )
21
+ #if arch(arm64)
22
+ let dylibPath = server. appending ( path: " bin/coder-vpn-arm64.dylib " )
23
+ #elseif arch(x86_64)
24
+ let dylibPath = server. appending ( path: " bin/coder-vpn-amd64.dylib " )
25
+ #else
26
+ fatalError ( " unknown architecture " )
27
+ #endif
28
+ do {
29
+ try await downloader. download ( src: dylibPath, dest: dest)
30
+ } catch {
31
+ throw . download( error)
32
+ }
33
+ do {
34
+ try tunnelHandle = TunnelHandle ( dylibPath: dest)
35
+ } catch {
36
+ throw . tunnelSetup( error)
37
+ }
38
+ speaker = await Speaker < Vpn_ManagerMessage , Vpn_TunnelMessage > (
39
+ writeFD: tunnelHandle. writeHandle,
40
+ readFD: tunnelHandle. readHandle
41
+ )
42
+ // TODO: Handshake
43
+ // do throws(HandshakeError) {
44
+ // try await speaker.handshake()
45
+ // } catch {
46
+ // throw .handshake(<#T##HandshakeError#>)
47
+ // }
48
+ readLoop = Task {
49
+ for try await m in speaker {
50
+ switch m {
51
+ case let . message( msg) :
52
+ handleMessage ( msg)
53
+ case let . RPC( rpc) :
54
+ handleRPC ( rpc)
55
+ }
56
+ }
57
+ }
20
58
}
59
+
60
+ func handleMessage( _ msg: Vpn_TunnelMessage ) {
61
+ guard let msgType = msg. msg else {
62
+ logger. critical ( " received message with no type " )
63
+ return
64
+ }
65
+ switch msgType {
66
+ case . peerUpdate:
67
+ { } ( ) // TODO: Send over XPC
68
+ case let . log( logMsg) :
69
+ writeVpnLog ( logMsg)
70
+ case . networkSettings, . start, . stop:
71
+ logger. critical ( " received unexpected message ` \( String ( describing: msgType) ) ` " )
72
+ }
73
+ }
74
+
75
+ func handleRPC( _ rpc: RPCRequest < Vpn_ManagerMessage , Vpn_TunnelMessage > ) {
76
+ guard let msgType = rpc. msg. msg else {
77
+ logger. critical ( " received rpc with no type " )
78
+ return
79
+ }
80
+ switch msgType {
81
+ case let . networkSettings( ns) :
82
+ let neSettings = convertNetworkSettingsRequest ( ns)
83
+ ptp. setTunnelNetworkSettings ( neSettings)
84
+ case . log, . peerUpdate, . start, . stop:
85
+ logger. critical ( " received unexpected rpc: ` \( String ( describing: msgType) ) ` " )
86
+ }
87
+ }
88
+
89
+ // TODO:
90
+ func startVPN( ) throws { }
91
+ func stopVPN( ) throws { }
92
+ }
93
+
94
+ enum ManagerError : Error {
95
+ case download( DownloadError )
96
+ case tunnelSetup( TunnelHandleError )
97
+ case handshake( HandshakeError )
98
+ }
99
+
100
+ func writeVpnLog( _ log: Vpn_Log ) {
101
+ let level : OSLogType = switch log. level {
102
+ case . info: . info
103
+ case . debug: . debug
104
+ // warn == error
105
+ case . warn: . error
106
+ case . error: . error
107
+ // critical == fatal == fault
108
+ case . critical: . fault
109
+ case . fatal: . fault
110
+ case . UNRECOGNIZED: . info
111
+ }
112
+ let logger = Logger (
113
+ subsystem: " \( Bundle . main. bundleIdentifier!) .dylib " ,
114
+ category: log. loggerNames. joined ( separator: " . " )
115
+ )
116
+ let fields = log. fields. map { " \( $0. name) : \( $0. value) " } . joined ( separator: " , " )
117
+ logger. log ( level: level, " \( log. message) : \( fields) " )
21
118
}
0 commit comments