@@ -25,6 +25,15 @@ class AppState: ObservableObject {
25
25
}
26
26
}
27
27
28
+ @Published private( set) var hostnameSuffix : String {
29
+ didSet {
30
+ guard persistent else { return }
31
+ UserDefaults . standard. set ( hostnameSuffix, forKey: Keys . hostnameSuffix)
32
+ }
33
+ }
34
+
35
+ static let defaultHostnameSuffix : String = " coder "
36
+
28
37
// Stored in Keychain
29
38
@Published private( set) var sessionToken : String ? {
30
39
didSet {
@@ -33,6 +42,8 @@ class AppState: ObservableObject {
33
42
}
34
43
}
35
44
45
+ var client : Client ?
46
+
36
47
@Published var useLiteralHeaders : Bool = UserDefaults . standard. bool ( forKey: Keys . useLiteralHeaders) {
37
48
didSet {
38
49
reconfigure ( )
@@ -80,7 +91,7 @@ class AppState: ObservableObject {
80
91
private let keychain : Keychain
81
92
private let persistent : Bool
82
93
83
- let onChange : ( ( NETunnelProviderProtocol ? ) -> Void ) ?
94
+ private let onChange : ( ( NETunnelProviderProtocol ? ) -> Void ) ?
84
95
85
96
// reconfigure must be called when any property used to configure the VPN changes
86
97
public func reconfigure( ) {
@@ -94,6 +105,10 @@ class AppState: ObservableObject {
94
105
self . onChange = onChange
95
106
keychain = Keychain ( service: Bundle . main. bundleIdentifier!)
96
107
_hasSession = Published ( initialValue: persistent ? UserDefaults . standard. bool ( forKey: Keys . hasSession) : false )
108
+ _hostnameSuffix = Published (
109
+ initialValue: persistent ? UserDefaults . standard
110
+ . string ( forKey: Keys . hostnameSuffix) ?? Self . defaultHostnameSuffix : Self . defaultHostnameSuffix
111
+ )
97
112
_baseAccessURL = Published (
98
113
initialValue: persistent ? UserDefaults . standard. url ( forKey: Keys . baseAccessURL) : nil
99
114
)
@@ -107,21 +122,30 @@ class AppState: ObservableObject {
107
122
if sessionToken == nil || sessionToken!. isEmpty == true {
108
123
clearSession ( )
109
124
}
125
+ client = Client (
126
+ url: baseAccessURL!,
127
+ token: sessionToken!,
128
+ headers: useLiteralHeaders ? literalHeaders. map { $0. toSDKHeader ( ) } : [ ]
129
+ )
110
130
}
111
131
}
112
132
113
133
public func login( baseAccessURL: URL , sessionToken: String ) {
114
134
hasSession = true
115
135
self . baseAccessURL = baseAccessURL
116
136
self . sessionToken = sessionToken
137
+ client = Client (
138
+ url: baseAccessURL,
139
+ token: sessionToken,
140
+ headers: useLiteralHeaders ? literalHeaders. map { $0. toSDKHeader ( ) } : [ ]
141
+ )
117
142
reconfigure ( )
118
143
}
119
144
120
145
public func handleTokenExpiry( ) async {
121
146
if hasSession {
122
- let client = Client ( url: baseAccessURL!, token: sessionToken!)
123
147
do {
124
- _ = try await client. user ( " me " )
148
+ _ = try await client! . user ( " me " )
125
149
} catch let SDKError . api( apiErr) {
126
150
// Expired token
127
151
if apiErr. statusCode == 401 {
@@ -135,9 +159,24 @@ class AppState: ObservableObject {
135
159
}
136
160
}
137
161
162
+ public func refreshDeploymentConfig( ) async {
163
+ if hasSession {
164
+ do {
165
+ let config = try await client!. sshConfiguration ( )
166
+ hostnameSuffix = config. hostname_suffix ?? Self . defaultHostnameSuffix
167
+ } catch {
168
+ // If fetching the config fails, there's likely a bigger issue.
169
+ // We'll show an error in the UI if they try and do something
170
+ logger. error ( " failed to refresh deployment config: \( error) " )
171
+ return
172
+ }
173
+ }
174
+ }
175
+
138
176
public func clearSession( ) {
139
177
hasSession = false
140
178
sessionToken = nil
179
+ client = nil
141
180
reconfigure ( )
142
181
}
143
182
@@ -159,6 +198,7 @@ class AppState: ObservableObject {
159
198
static let hasSession = " hasSession "
160
199
static let baseAccessURL = " baseAccessURL "
161
200
static let sessionToken = " sessionToken "
201
+ static let hostnameSuffix = " hostnameSuffix "
162
202
163
203
static let useLiteralHeaders = " UseLiteralHeaders "
164
204
static let literalHeaders = " LiteralHeaders "
0 commit comments