@@ -6,16 +6,113 @@ actor Manager {
66 let ptp : PacketTunnelProvider
77 let downloader : Downloader
88
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 > !
1112 // TODO: XPC Speaker
1213
1314 private let dest = FileManager . default. urls ( for: . documentDirectory, in: . userDomainMask)
1415 . first!. appending ( path: " coder-vpn.dylib " )
1516 private let logger = Logger ( subsystem: Bundle . main. bundleIdentifier!, category: " manager " )
1617
17- init ( with: PacketTunnelProvider ) {
18+ init ( with: PacketTunnelProvider , server : URL ) async throws ( ManagerError ) {
1819 ptp = with
1920 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+ }
2058 }
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) " )
21118}
0 commit comments