forked from tangled.org/core
this repo has no description
1package knotclient 2 3import ( 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 17type UnsignedClient struct { 18 Url *url.URL 19 client *http.Client 20} 21 22func 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 44func (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 55func 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 78func (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 96func (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 115func (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 130func (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 resp, err := us.client.Do(req) 143 if err != nil { 144 return nil, err 145 } 146 147 body, err := io.ReadAll(resp.Body) 148 if err != nil { 149 return nil, err 150 } 151 152 var result types.RepoTagsResponse 153 err = json.Unmarshal(body, &result) 154 if err != nil { 155 return nil, err 156 } 157 158 return &result, nil 159} 160 161func (us *UnsignedClient) Branch(ownerDid, repoName, branch string) (*http.Response, error) { 162 const ( 163 Method = "GET" 164 ) 165 166 endpoint := fmt.Sprintf("/%s/%s/branches/%s", ownerDid, repoName, url.PathEscape(branch)) 167 168 req, err := us.newRequest(Method, endpoint, nil, nil) 169 if err != nil { 170 return nil, err 171 } 172 173 return us.client.Do(req) 174} 175 176func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*types.RepoDefaultBranchResponse, error) { 177 const ( 178 Method = "GET" 179 ) 180 181 endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) 182 183 req, err := us.newRequest(Method, endpoint, nil, nil) 184 if err != nil { 185 return nil, err 186 } 187 188 resp, err := us.client.Do(req) 189 if err != nil { 190 return nil, err 191 } 192 defer resp.Body.Close() 193 194 var defaultBranch types.RepoDefaultBranchResponse 195 if err := json.NewDecoder(resp.Body).Decode(&defaultBranch); err != nil { 196 return nil, err 197 } 198 199 return &defaultBranch, nil 200} 201 202func (us *UnsignedClient) Capabilities() (*types.Capabilities, error) { 203 const ( 204 Method = "GET" 205 Endpoint = "/capabilities" 206 ) 207 208 req, err := us.newRequest(Method, Endpoint, nil, nil) 209 if err != nil { 210 return nil, err 211 } 212 213 resp, err := us.client.Do(req) 214 if err != nil { 215 return nil, err 216 } 217 defer resp.Body.Close() 218 219 var capabilities types.Capabilities 220 if err := json.NewDecoder(resp.Body).Decode(&capabilities); err != nil { 221 return nil, err 222 } 223 224 return &capabilities, nil 225} 226 227func (us *UnsignedClient) Compare(ownerDid, repoName, rev1, rev2 string) (*types.RepoFormatPatchResponse, error) { 228 const ( 229 Method = "GET" 230 ) 231 232 endpoint := fmt.Sprintf("/%s/%s/compare/%s/%s", ownerDid, repoName, url.PathEscape(rev1), url.PathEscape(rev2)) 233 234 req, err := us.newRequest(Method, endpoint, nil, nil) 235 if err != nil { 236 return nil, fmt.Errorf("Failed to create request.") 237 } 238 239 compareResp, err := us.client.Do(req) 240 if err != nil { 241 return nil, fmt.Errorf("Failed to create request.") 242 } 243 defer compareResp.Body.Close() 244 245 switch compareResp.StatusCode { 246 case 404: 247 case 400: 248 return nil, fmt.Errorf("Branch comparisons not supported on this knot.") 249 } 250 251 respBody, err := io.ReadAll(compareResp.Body) 252 if err != nil { 253 log.Println("failed to compare across branches") 254 return nil, fmt.Errorf("Failed to compare branches.") 255 } 256 defer compareResp.Body.Close() 257 258 var formatPatchResponse types.RepoFormatPatchResponse 259 err = json.Unmarshal(respBody, &formatPatchResponse) 260 if err != nil { 261 log.Println("failed to unmarshal format-patch response", err) 262 return nil, fmt.Errorf("failed to compare branches.") 263 } 264 265 return &formatPatchResponse, nil 266}