-285
knotclient/unsigned.go
-285
knotclient/unsigned.go
···
1
-
package knotclient
2
-
3
-
import (
4
-
"bytes"
5
-
"encoding/json"
6
-
"fmt"
7
-
"io"
8
-
"log"
9
-
"net/http"
10
-
"net/url"
11
-
"strconv"
12
-
"time"
13
-
14
-
"tangled.sh/tangled.sh/core/types"
15
-
)
16
-
17
-
type UnsignedClient struct {
18
-
Url *url.URL
19
-
client *http.Client
20
-
}
21
-
22
-
func NewUnsignedClient(domain string, dev bool) (*UnsignedClient, error) {
23
-
client := &http.Client{
24
-
Timeout: 5 * time.Second,
25
-
}
26
-
27
-
scheme := "https"
28
-
if dev {
29
-
scheme = "http"
30
-
}
31
-
url, err := url.Parse(fmt.Sprintf("%s://%s", scheme, domain))
32
-
if err != nil {
33
-
return nil, err
34
-
}
35
-
36
-
unsignedClient := &UnsignedClient{
37
-
client: client,
38
-
Url: url,
39
-
}
40
-
41
-
return unsignedClient, nil
42
-
}
43
-
44
-
func (us *UnsignedClient) newRequest(method, endpoint string, query url.Values, body []byte) (*http.Request, error) {
45
-
reqUrl := us.Url.JoinPath(endpoint)
46
-
47
-
// add query parameters
48
-
if query != nil {
49
-
reqUrl.RawQuery = query.Encode()
50
-
}
51
-
52
-
return http.NewRequest(method, reqUrl.String(), bytes.NewReader(body))
53
-
}
54
-
55
-
func do[T any](us *UnsignedClient, req *http.Request) (*T, error) {
56
-
resp, err := us.client.Do(req)
57
-
if err != nil {
58
-
return nil, err
59
-
}
60
-
defer resp.Body.Close()
61
-
62
-
body, err := io.ReadAll(resp.Body)
63
-
if err != nil {
64
-
log.Printf("Error reading response body: %v", err)
65
-
return nil, err
66
-
}
67
-
68
-
var result T
69
-
err = json.Unmarshal(body, &result)
70
-
if err != nil {
71
-
log.Printf("Error unmarshalling response body: %v", err)
72
-
return nil, err
73
-
}
74
-
75
-
return &result, nil
76
-
}
77
-
78
-
func (us *UnsignedClient) Index(ownerDid, repoName, ref string) (*types.RepoIndexResponse, error) {
79
-
const (
80
-
Method = "GET"
81
-
)
82
-
83
-
endpoint := fmt.Sprintf("/%s/%s/tree/%s", ownerDid, repoName, ref)
84
-
if ref == "" {
85
-
endpoint = fmt.Sprintf("/%s/%s", ownerDid, repoName)
86
-
}
87
-
88
-
req, err := us.newRequest(Method, endpoint, nil, nil)
89
-
if err != nil {
90
-
return nil, err
91
-
}
92
-
93
-
return do[types.RepoIndexResponse](us, req)
94
-
}
95
-
96
-
func (us *UnsignedClient) Log(ownerDid, repoName, ref string, page int) (*types.RepoLogResponse, error) {
97
-
const (
98
-
Method = "GET"
99
-
)
100
-
101
-
endpoint := fmt.Sprintf("/%s/%s/log/%s", ownerDid, repoName, url.PathEscape(ref))
102
-
103
-
query := url.Values{}
104
-
query.Add("page", strconv.Itoa(page))
105
-
query.Add("per_page", strconv.Itoa(60))
106
-
107
-
req, err := us.newRequest(Method, endpoint, query, nil)
108
-
if err != nil {
109
-
return nil, err
110
-
}
111
-
112
-
return do[types.RepoLogResponse](us, req)
113
-
}
114
-
115
-
func (us *UnsignedClient) Branches(ownerDid, repoName string) (*types.RepoBranchesResponse, error) {
116
-
const (
117
-
Method = "GET"
118
-
)
119
-
120
-
endpoint := fmt.Sprintf("/%s/%s/branches", ownerDid, repoName)
121
-
122
-
req, err := us.newRequest(Method, endpoint, nil, nil)
123
-
if err != nil {
124
-
return nil, err
125
-
}
126
-
127
-
return do[types.RepoBranchesResponse](us, req)
128
-
}
129
-
130
-
func (us *UnsignedClient) Tags(ownerDid, repoName string) (*types.RepoTagsResponse, error) {
131
-
const (
132
-
Method = "GET"
133
-
)
134
-
135
-
endpoint := fmt.Sprintf("/%s/%s/tags", ownerDid, repoName)
136
-
137
-
req, err := us.newRequest(Method, endpoint, nil, nil)
138
-
if err != nil {
139
-
return nil, err
140
-
}
141
-
142
-
return do[types.RepoTagsResponse](us, req)
143
-
}
144
-
145
-
func (us *UnsignedClient) Branch(ownerDid, repoName, branch string) (*types.RepoBranchResponse, error) {
146
-
const (
147
-
Method = "GET"
148
-
)
149
-
150
-
endpoint := fmt.Sprintf("/%s/%s/branches/%s", ownerDid, repoName, url.PathEscape(branch))
151
-
152
-
req, err := us.newRequest(Method, endpoint, nil, nil)
153
-
if err != nil {
154
-
return nil, err
155
-
}
156
-
157
-
return do[types.RepoBranchResponse](us, req)
158
-
}
159
-
160
-
func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*types.RepoDefaultBranchResponse, error) {
161
-
const (
162
-
Method = "GET"
163
-
)
164
-
165
-
endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName)
166
-
167
-
req, err := us.newRequest(Method, endpoint, nil, nil)
168
-
if err != nil {
169
-
return nil, err
170
-
}
171
-
172
-
resp, err := us.client.Do(req)
173
-
if err != nil {
174
-
return nil, err
175
-
}
176
-
defer resp.Body.Close()
177
-
178
-
var defaultBranch types.RepoDefaultBranchResponse
179
-
if err := json.NewDecoder(resp.Body).Decode(&defaultBranch); err != nil {
180
-
return nil, err
181
-
}
182
-
183
-
return &defaultBranch, nil
184
-
}
185
-
186
-
func (us *UnsignedClient) Capabilities() (*types.Capabilities, error) {
187
-
const (
188
-
Method = "GET"
189
-
Endpoint = "/capabilities"
190
-
)
191
-
192
-
req, err := us.newRequest(Method, Endpoint, nil, nil)
193
-
if err != nil {
194
-
return nil, err
195
-
}
196
-
197
-
resp, err := us.client.Do(req)
198
-
if err != nil {
199
-
return nil, err
200
-
}
201
-
defer resp.Body.Close()
202
-
203
-
var capabilities types.Capabilities
204
-
if err := json.NewDecoder(resp.Body).Decode(&capabilities); err != nil {
205
-
return nil, err
206
-
}
207
-
208
-
return &capabilities, nil
209
-
}
210
-
211
-
func (us *UnsignedClient) Compare(ownerDid, repoName, rev1, rev2 string) (*types.RepoFormatPatchResponse, error) {
212
-
const (
213
-
Method = "GET"
214
-
)
215
-
216
-
endpoint := fmt.Sprintf("/%s/%s/compare/%s/%s", ownerDid, repoName, url.PathEscape(rev1), url.PathEscape(rev2))
217
-
218
-
req, err := us.newRequest(Method, endpoint, nil, nil)
219
-
if err != nil {
220
-
return nil, fmt.Errorf("Failed to create request.")
221
-
}
222
-
223
-
compareResp, err := us.client.Do(req)
224
-
if err != nil {
225
-
return nil, fmt.Errorf("Failed to create request.")
226
-
}
227
-
defer compareResp.Body.Close()
228
-
229
-
switch compareResp.StatusCode {
230
-
case 404:
231
-
case 400:
232
-
return nil, fmt.Errorf("Branch comparisons not supported on this knot.")
233
-
}
234
-
235
-
respBody, err := io.ReadAll(compareResp.Body)
236
-
if err != nil {
237
-
log.Println("failed to compare across branches")
238
-
return nil, fmt.Errorf("Failed to compare branches.")
239
-
}
240
-
defer compareResp.Body.Close()
241
-
242
-
var formatPatchResponse types.RepoFormatPatchResponse
243
-
err = json.Unmarshal(respBody, &formatPatchResponse)
244
-
if err != nil {
245
-
log.Println("failed to unmarshal format-patch response", err)
246
-
return nil, fmt.Errorf("failed to compare branches.")
247
-
}
248
-
249
-
return &formatPatchResponse, nil
250
-
}
251
-
252
-
func (s *UnsignedClient) RepoLanguages(ownerDid, repoName, ref string) (*types.RepoLanguageResponse, error) {
253
-
const (
254
-
Method = "GET"
255
-
)
256
-
endpoint := fmt.Sprintf("/%s/%s/languages/%s", ownerDid, repoName, url.PathEscape(ref))
257
-
258
-
req, err := s.newRequest(Method, endpoint, nil, nil)
259
-
if err != nil {
260
-
return nil, err
261
-
}
262
-
263
-
resp, err := s.client.Do(req)
264
-
if err != nil {
265
-
return nil, err
266
-
}
267
-
268
-
var result types.RepoLanguageResponse
269
-
if resp.StatusCode != http.StatusOK {
270
-
log.Println("failed to calculate languages", resp.Status)
271
-
return &types.RepoLanguageResponse{}, nil
272
-
}
273
-
274
-
body, err := io.ReadAll(resp.Body)
275
-
if err != nil {
276
-
return nil, err
277
-
}
278
-
279
-
err = json.Unmarshal(body, &result)
280
-
if err != nil {
281
-
return nil, err
282
-
}
283
-
284
-
return &result, nil
285
-
}
···