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

Commit918bacd

Browse files
refactor(CoderSDK): share code between Client and AgentClient (#132)
Refactor to address review feedback that `AgentClient` extending the regular `Client` was confusing.
1 parent8067574 commit918bacd

File tree

11 files changed

+167
-102
lines changed

11 files changed

+167
-102
lines changed

‎Coder-Desktop/Coder-Desktop/State.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class AppState: ObservableObject {
122122
letclient=Client(url: baseAccessURL!, token: sessionToken!)
123123
do{
124124
_=tryawait client.user("me")
125-
}catchletClientError.api(apiErr){
125+
}catchletSDKError.api(apiErr){
126126
// Expired token
127127
if apiErr.statusCode==401{
128128
clearSession()

‎Coder-Desktop/Coder-Desktop/Views/FileSync/FilePicker.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ struct FilePicker: View {
7272
classFilePickerModel:ObservableObject{
7373
@PublishedvarrootEntries:[FilePickerEntryModel]=[]
7474
@PublishedvarrootIsLoading:Bool=false
75-
@Publishedvarerror:ClientError?
75+
@Publishedvarerror:SDKError?
7676

7777
// It's important that `AgentClient` is a reference type (class)
7878
// as we were having performance issues with a struct (unless it was a binding).
@@ -87,7 +87,7 @@ class FilePickerModel: ObservableObject {
8787
rootIsLoading=true
8888
Task{
8989
defer{ rootIsLoading=false}
90-
dothrows(ClientError){
90+
dothrows(SDKError){
9191
rootEntries=tryawait client
9292
.listAgentDirectory(.init(path:[], relativity:.root))
9393
.toModels(client: client)
@@ -149,7 +149,7 @@ class FilePickerEntryModel: Identifiable, Hashable, ObservableObject {
149149

150150
@Publishedvarentries:[FilePickerEntryModel]?
151151
@PublishedvarisLoading=false
152-
@Publishedvarerror:ClientError?
152+
@Publishedvarerror:SDKError?
153153
@PublishedprivatevarinnerIsExpanded=false
154154
varisExpanded:Bool{
155155
get{ innerIsExpanded}
@@ -193,7 +193,7 @@ class FilePickerEntryModel: Identifiable, Hashable, ObservableObject {
193193
innerIsExpanded=true
194194
}
195195
}
196-
dothrows(ClientError){
196+
dothrows(SDKError){
197197
entries=tryawait client
198198
.listAgentDirectory(.init(path: path, relativity:.root))
199199
.toModels(client: client)

‎Coder-Desktop/Coder-Desktop/Views/LoginForm.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ enum LoginError: Error {
207207
case invalidURL
208208
case outdatedCoderVersion
209209
case missingServerVersion
210-
case failedAuth(ClientError)
210+
case failedAuth(SDKError)
211211

212212
vardescription:String{
213213
switchself{

‎Coder-Desktop/Coder-DesktopTests/FilePickerTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct FilePickerTests {
6060
tryMock(
6161
url: url.appendingPathComponent("/api/v0/list-directory"),
6262
statusCode:200,
63-
data:[.post:Client.encoder.encode(mockResponse)]
63+
data:[.post:CoderSDK.encoder.encode(mockResponse)]
6464
).register()
6565

6666
tryawaitViewHosting.host(view){
@@ -88,7 +88,7 @@ struct FilePickerTests {
8888
tryMock(
8989
url: url.appendingPathComponent("/api/v0/list-directory"),
9090
statusCode:200,
91-
data:[.post:Client.encoder.encode(mockResponse)]
91+
data:[.post:CoderSDK.encoder.encode(mockResponse)]
9292
).register()
9393

9494
tryawaitViewHosting.host(view){

‎Coder-Desktop/Coder-DesktopTests/LoginFormTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ struct LoginTests {
7979
tryMock(
8080
url: url.appendingPathComponent("/api/v2/buildinfo"),
8181
statusCode:200,
82-
data:[.get:Client.encoder.encode(buildInfo)]
82+
data:[.get:CoderSDK.encoder.encode(buildInfo)]
8383
).register()
8484
Mock(url: url.appendingPathComponent("/api/v2/users/me"), statusCode:401, data:[.get:Data()]).register()
8585

@@ -104,13 +104,13 @@ struct LoginTests {
104104
tryMock(
105105
url: url.appendingPathComponent("/api/v2/buildinfo"),
106106
statusCode:200,
107-
data:[.get:Client.encoder.encode(buildInfo)]
107+
data:[.get:CoderSDK.encoder.encode(buildInfo)]
108108
).register()
109109

110110
tryMock(
111111
url: url.appendingPathComponent("/api/v2/users/me"),
112112
statusCode:200,
113-
data:[.get:Client.encoder.encode(User(id:UUID(), username:"username"))]
113+
data:[.get:CoderSDK.encoder.encode(User(id:UUID(), username:"username"))]
114114
).register()
115115

116116
tryawaitViewHosting.host(view){
@@ -140,13 +140,13 @@ struct LoginTests {
140140
tryMock(
141141
url: url.appendingPathComponent("/api/v2/users/me"),
142142
statusCode:200,
143-
data:[.get:Client.encoder.encode(user)]
143+
data:[.get:CoderSDK.encoder.encode(user)]
144144
).register()
145145

146146
tryMock(
147147
url: url.appendingPathComponent("/api/v2/buildinfo"),
148148
statusCode:200,
149-
data:[.get:Client.encoder.encode(buildInfo)]
149+
data:[.get:CoderSDK.encoder.encode(buildInfo)]
150150
).register()
151151

152152
tryawaitViewHosting.host(view){
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
publicfinalclassAgentClient:Sendable{
2-
letclient:Client
2+
letagentURL:URL
33

44
publicinit(agentHost:String){
5-
client=Client(url:URL(string:"http://\(agentHost):4")!)
5+
agentURL=URL(string:"http://\(agentHost):4")!
6+
}
7+
8+
func request(
9+
_ path:String,
10+
method:HTTPMethod
11+
)asyncthrows(SDKError)->HTTPResponse{
12+
tryawaitCoderSDK.request(baseURL: agentURL, path: path, method: method)
13+
}
14+
15+
func request(
16+
_ path:String,
17+
method:HTTPMethod,
18+
body:someEncodable&Sendable
19+
)asyncthrows(SDKError)->HTTPResponse{
20+
tryawaitCoderSDK.request(baseURL: agentURL, path: path, method: method, body: body)
621
}
722
}

‎Coder-Desktop/CoderSDK/AgentLS.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
publicextensionAgentClient{
2-
func listAgentDirectory(_ req:LSRequest)asyncthrows(ClientError)->LSResponse{
3-
letres=tryawaitclient.request("/api/v0/list-directory", method:.post, body: req)
2+
func listAgentDirectory(_ req:LSRequest)asyncthrows(SDKError)->LSResponse{
3+
letres=tryawaitrequest("/api/v0/list-directory", method:.post, body: req)
44
guard res.resp.statusCode==200else{
5-
throwclient.responseAsError(res)
5+
throwresponseAsError(res)
66
}
7-
returntryclient.decode(LSResponse.self, from: res.data)
7+
returntrydecode(LSResponse.self, from: res.data)
88
}
99
}
1010

‎Coder-Desktop/CoderSDK/Client.swift

Lines changed: 129 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -11,95 +11,38 @@ public struct Client: Sendable {
1111
self.headers= headers
1212
}
1313

14-
staticletdecoder:JSONDecoder={
15-
vardec=JSONDecoder()
16-
dec.dateDecodingStrategy=.iso8601withOptionalFractionalSeconds
17-
return dec
18-
}()
19-
20-
staticletencoder:JSONEncoder={
21-
varenc=JSONEncoder()
22-
enc.dateEncodingStrategy=.iso8601withFractionalSeconds
23-
return enc
24-
}()
25-
26-
privatefunc doRequest(
27-
path:String,
28-
method:HTTPMethod,
29-
body:Data?=nil
30-
)asyncthrows(ClientError)->HTTPResponse{
31-
leturl= url.appendingPathComponent(path)
32-
varreq=URLRequest(url: url)
33-
iflet token{ req.addValue(token, forHTTPHeaderField:Headers.sessionToken)}
34-
req.httpMethod= method.rawValue
35-
forheaderin headers{
36-
req.addValue(header.value, forHTTPHeaderField: header.name)
37-
}
38-
req.httpBody= body
39-
letdata:Data
40-
letresp:URLResponse
41-
do{
42-
(data, resp)=tryawaitURLSession.shared.data(for: req)
43-
}catch{
44-
throw.network(error)
45-
}
46-
guardlet httpResponse= respas?HTTPURLResponseelse{
47-
throw.unexpectedResponse(String(data: data, encoding:.utf8)??"<non-utf8 data>")
48-
}
49-
returnHTTPResponse(resp: httpResponse, data: data, req: req)
50-
}
51-
5214
func request(
5315
_ path:String,
5416
method:HTTPMethod,
5517
body:someEncodable&Sendable
56-
)asyncthrows(ClientError)->HTTPResponse{
57-
letencodedBody:Data?
58-
do{
59-
encodedBody=tryClient.encoder.encode(body)
60-
}catch{
61-
throw.encodeFailure(error)
18+
)asyncthrows(SDKError)->HTTPResponse{
19+
varheaders= headers
20+
iflet token{
21+
headers+=[.init(name:Headers.sessionToken, value: token)]
6222
}
63-
returntryawaitdoRequest(path: path, method: method, body: encodedBody)
23+
returntryawaitCoderSDK.request(
24+
baseURL: url,
25+
path: path,
26+
method: method,
27+
headers: headers,
28+
body: body
29+
)
6430
}
6531

6632
func request(
6733
_ path:String,
6834
method:HTTPMethod
69-
)asyncthrows(ClientError)->HTTPResponse{
70-
tryawaitdoRequest(path: path, method: method)
71-
}
72-
73-
func responseAsError(_ resp:HTTPResponse)->ClientError{
74-
do{
75-
letbody=trydecode(Response.self, from: resp.data)
76-
letout=APIError(
77-
response: body,
78-
statusCode: resp.resp.statusCode,
79-
method: resp.req.httpMethod!,
80-
url: resp.req.url!
81-
)
82-
return.api(out)
83-
}catch{
84-
return.unexpectedResponse(String(data: resp.data, encoding:.utf8)??"<non-utf8 data>")
85-
}
86-
}
87-
88-
// Wrapper around JSONDecoder.decode that displays useful error messages from `DecodingError`.
89-
func decode<T>(_:T.Type, from data:Data)throws(ClientError)->Twhere T:Decodable{
90-
do{
91-
returntryClient.decoder.decode(T.self, from: data)
92-
}catchletDecodingError.keyNotFound(_, context){
93-
throw.unexpectedResponse("Key not found:\(context.debugDescription)")
94-
}catchletDecodingError.valueNotFound(_, context){
95-
throw.unexpectedResponse("Value not found:\(context.debugDescription)")
96-
}catchletDecodingError.typeMismatch(_, context){
97-
throw.unexpectedResponse("Type mismatch:\(context.debugDescription)")
98-
}catchletDecodingError.dataCorrupted(context){
99-
throw.unexpectedResponse("Data corrupted:\(context.debugDescription)")
100-
}catch{
101-
throw.unexpectedResponse(String(data: data.prefix(1024), encoding:.utf8)??"<non-utf8 data>")
35+
)asyncthrows(SDKError)->HTTPResponse{
36+
varheaders= headers
37+
iflet token{
38+
headers+=[.init(name:Headers.sessionToken, value: token)]
10239
}
40+
returntryawaitCoderSDK.request(
41+
baseURL: url,
42+
path: path,
43+
method: method,
44+
headers: headers
45+
)
10346
}
10447
}
10548

@@ -133,7 +76,7 @@ public struct FieldValidation: Decodable, Sendable {
13376
letdetail:String
13477
}
13578

136-
publicenumClientError:Error{
79+
publicenumSDKError:Error{
13780
case api(APIError)
13881
case network(anyError)
13982
case unexpectedResponse(String)
@@ -154,3 +97,110 @@ public enum ClientError: Error {
15497

15598
publicvarlocalizedDescription:String{ description}
15699
}
100+
101+
letdecoder:JSONDecoder={
102+
vardec=JSONDecoder()
103+
dec.dateDecodingStrategy=.iso8601withOptionalFractionalSeconds
104+
return dec
105+
}()
106+
107+
letencoder:JSONEncoder={
108+
varenc=JSONEncoder()
109+
enc.dateEncodingStrategy=.iso8601withFractionalSeconds
110+
return enc
111+
}()
112+
113+
func doRequest(
114+
baseURL:URL,
115+
path:String,
116+
method:HTTPMethod,
117+
headers:[HTTPHeader]=[],
118+
body:Data?=nil
119+
)asyncthrows(SDKError)->HTTPResponse{
120+
leturl= baseURL.appendingPathComponent(path)
121+
varreq=URLRequest(url: url)
122+
req.httpMethod= method.rawValue
123+
forheaderin headers{
124+
req.addValue(header.value, forHTTPHeaderField: header.name)
125+
}
126+
req.httpBody= body
127+
letdata:Data
128+
letresp:URLResponse
129+
do{
130+
(data, resp)=tryawaitURLSession.shared.data(for: req)
131+
}catch{
132+
throw.network(error)
133+
}
134+
guardlet httpResponse= respas?HTTPURLResponseelse{
135+
throw.unexpectedResponse(String(data: data, encoding:.utf8)??"<non-utf8 data>")
136+
}
137+
returnHTTPResponse(resp: httpResponse, data: data, req: req)
138+
}
139+
140+
func request(
141+
baseURL:URL,
142+
path:String,
143+
method:HTTPMethod,
144+
headers:[HTTPHeader]=[],
145+
body:someEncodable&Sendable
146+
)asyncthrows(SDKError)->HTTPResponse{
147+
letencodedBody:Data
148+
do{
149+
encodedBody=try encoder.encode(body)
150+
}catch{
151+
throw.encodeFailure(error)
152+
}
153+
returntryawaitdoRequest(
154+
baseURL: baseURL,
155+
path: path,
156+
method: method,
157+
headers: headers,
158+
body: encodedBody
159+
)
160+
}
161+
162+
func request(
163+
baseURL:URL,
164+
path:String,
165+
method:HTTPMethod,
166+
headers:[HTTPHeader]=[]
167+
)asyncthrows(SDKError)->HTTPResponse{
168+
tryawaitdoRequest(
169+
baseURL: baseURL,
170+
path: path,
171+
method: method,
172+
headers: headers
173+
)
174+
}
175+
176+
func responseAsError(_ resp:HTTPResponse)->SDKError{
177+
do{
178+
letbody=trydecode(Response.self, from: resp.data)
179+
letout=APIError(
180+
response: body,
181+
statusCode: resp.resp.statusCode,
182+
method: resp.req.httpMethod!,
183+
url: resp.req.url!
184+
)
185+
return.api(out)
186+
}catch{
187+
return.unexpectedResponse(String(data: resp.data, encoding:.utf8)??"<non-utf8 data>")
188+
}
189+
}
190+
191+
// Wrapper around JSONDecoder.decode that displays useful error messages from `DecodingError`.
192+
func decode<T:Decodable>(_:T.Type, from data:Data)throws(SDKError)->T{
193+
do{
194+
returntry decoder.decode(T.self, from: data)
195+
}catchletDecodingError.keyNotFound(_, context){
196+
throw.unexpectedResponse("Key not found:\(context.debugDescription)")
197+
}catchletDecodingError.valueNotFound(_, context){
198+
throw.unexpectedResponse("Value not found:\(context.debugDescription)")
199+
}catchletDecodingError.typeMismatch(_, context){
200+
throw.unexpectedResponse("Type mismatch:\(context.debugDescription)")
201+
}catchletDecodingError.dataCorrupted(context){
202+
throw.unexpectedResponse("Data corrupted:\(context.debugDescription)")
203+
}catch{
204+
throw.unexpectedResponse(String(data: data.prefix(1024), encoding:.utf8)??"<non-utf8 data>")
205+
}
206+
}

‎Coder-Desktop/CoderSDK/Deployment.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22

33
publicextensionClient{
4-
func buildInfo()asyncthrows(ClientError)->BuildInfoResponse{
4+
func buildInfo()asyncthrows(SDKError)->BuildInfoResponse{
55
letres=tryawaitrequest("/api/v2/buildinfo", method:.get)
66
guard res.resp.statusCode==200else{
77
throwresponseAsError(res)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp