github.com/cidverse/cid-sdk-go@v0.0.0-20240318001225-c193d83f053e/client.go (about) 1 package cidsdk 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "net/http" 11 "net/url" 12 "os" 13 "strconv" 14 "strings" 15 "time" 16 17 "github.com/go-resty/resty/v2" 18 ) 19 20 func NewSDK() (*SDK, error) { 21 client := resty.New() 22 client.SetDisableWarn(true) 23 client.SetRetryCount(0) 24 client.SetTimeout(60 * time.Minute) 25 26 // socket endpoint 27 unixSocket := os.Getenv("CID_API_SOCKET") 28 if len(unixSocket) > 0 { 29 transport := http.Transport{ 30 DialContext: func(_ context.Context, _ string, _ string) (net.Conn, error) { 31 return net.Dial("unix", unixSocket) 32 }, 33 } 34 35 // base url 36 client.SetTransport(&transport).SetBaseURL("http://localhost") 37 } 38 39 // http endpoint 40 addr := os.Getenv("CID_API_ADDR") 41 if len(addr) > 0 { 42 client.SetBaseURL(addr) 43 } 44 45 // auth 46 secret := os.Getenv("CID_API_SECRET") 47 if len(secret) > 0 { 48 client.SetAuthScheme("Bearer") 49 client.SetAuthToken(secret) 50 } 51 52 if client == nil { 53 return nil, errors.New("failed to initialize api client") 54 } 55 return &SDK{client: client}, nil 56 } 57 58 type SDKClient interface { 59 Health() (*HealthcheckResponse, error) 60 Log(req LogMessageRequest) error 61 ModuleAction(cfg any) (ModuleActionData, error) 62 ProjectAction(cfg any) (ProjectActionData, error) 63 Env() (map[string]string, error) 64 Modules() (*[]ProjectModule, error) 65 CurrentModule() (*ProjectModule, error) 66 CurrentConfig() (*CurrentConfig, error) 67 VCSCommits(request VCSCommitsRequest) (*[]VCSCommit, error) 68 VCSCommitByHash(request VCSCommitByHashRequest) (*VCSCommit, error) 69 VCSTags() (*[]VCSTag, error) 70 VCSReleases(request VCSReleasesRequest) (*[]VCSRelease, error) 71 VCSDiff(request VCSDiffRequest) (*[]VCSDiff, error) 72 ExecuteCommand(req ExecuteCommandRequest) (*ExecuteCommandResponse, error) 73 FileRead(file string) (string, error) 74 FileList(req FileRequest) (files []File, err error) 75 FileRename(old string, new string) error 76 FileRemove(file string) error 77 FileWrite(file string, content []byte) error 78 FileExists(file string) bool 79 ZIPCreate(inputDirectory string, archiveFile string) error 80 ZIPExtract(archiveFile string, outputDirectory string) error 81 TARCreate(inputDirectory string, archiveFile string) error 82 TARExtract(archiveFile string, outputDirectory string) error 83 ArtifactList(request ArtifactListRequest) (*[]ActionArtifact, error) 84 ArtifactUpload(request ArtifactUploadRequest) error 85 ArtifactDownload(request ArtifactDownloadRequest) error 86 ArtifactDownloadByteArray(request ArtifactDownloadByteArrayRequest) ([]byte, error) 87 UUID() string 88 } 89 90 type SDK struct { 91 client *resty.Client 92 } 93 94 // Health request 95 func (sdk SDK) Health() (*HealthcheckResponse, error) { 96 resp, err := sdk.client.R(). 97 SetHeader("Accept", "application/json"). 98 SetResult(&HealthcheckResponse{}). 99 SetError(&APIError{}). 100 Get("/health") 101 102 if err != nil { 103 return nil, err 104 } else if resp.IsSuccess() { 105 fmt.Printf("RESULT: %+v\n", resp.Result()) 106 return resp.Result().(*HealthcheckResponse), nil 107 } else { 108 return nil, resp.Error().(*APIError) 109 } 110 } 111 112 // Env request 113 func (sdk SDK) Env() (map[string]string, error) { 114 resp, err := sdk.client.R(). 115 SetHeader("Accept", "application/json"). 116 SetResult(&map[string]string{}). 117 SetError(&APIError{}). 118 Get("/env") 119 120 if err != nil { 121 return nil, err 122 } else if resp.IsSuccess() { 123 return *resp.Result().(*map[string]string), nil 124 } else { 125 return nil, resp.Error().(*APIError) 126 } 127 } 128 129 // CurrentConfig request 130 func (sdk SDK) CurrentConfig() (*CurrentConfig, error) { 131 resp, err := sdk.client.R(). 132 SetHeader("Accept", "application/json"). 133 SetResult(&CurrentConfig{}). 134 SetError(&APIError{}). 135 Get("/config/current") 136 137 if err != nil { 138 return nil, err 139 } else if resp.IsSuccess() { 140 return resp.Result().(*CurrentConfig), nil 141 } else { 142 return nil, resp.Error().(*APIError) 143 } 144 } 145 146 // Modules request 147 func (sdk SDK) Modules() (*[]ProjectModule, error) { 148 resp, err := sdk.client.R(). 149 SetHeader("Accept", "application/json"). 150 SetResult(&[]ProjectModule{}). 151 SetError(&APIError{}). 152 Get("/module") 153 154 if err != nil { 155 return nil, err 156 } else if resp.IsSuccess() { 157 return resp.Result().(*[]ProjectModule), nil 158 } else { 159 return nil, resp.Error().(*APIError) 160 } 161 } 162 163 // CurrentModule request 164 func (sdk SDK) CurrentModule() (*ProjectModule, error) { 165 resp, err := sdk.client.R(). 166 SetHeader("Accept", "application/json"). 167 SetResult(&ProjectModule{}). 168 SetError(&APIError{}). 169 Get("/module/current") 170 171 if err != nil { 172 return nil, err 173 } else if resp.IsSuccess() { 174 return resp.Result().(*ProjectModule), nil 175 } else { 176 return nil, resp.Error().(*APIError) 177 } 178 } 179 180 type VCSCommitsRequest struct { 181 FromHash string `json:"from"` 182 ToHash string `json:"to"` 183 IncludeChanges bool `json:"changes"` 184 Limit int `json:"limit"` 185 } 186 187 // VCSCommits request 188 func (sdk SDK) VCSCommits(request VCSCommitsRequest) (*[]VCSCommit, error) { 189 resp, err := sdk.client.R(). 190 SetHeader("Accept", "application/json"). 191 SetResult(&[]VCSCommit{}). 192 SetError(&APIError{}). 193 Get(fmt.Sprintf("/vcs/commit?from=%s&to=%s&changes=%s&limit=%s", request.FromHash, request.ToHash, strconv.FormatBool(request.IncludeChanges), strconv.Itoa(request.Limit))) 194 195 if err != nil { 196 return nil, err 197 } else if resp.IsSuccess() { 198 return resp.Result().(*[]VCSCommit), nil 199 } else { 200 return nil, resp.Error().(*APIError) 201 } 202 } 203 204 type VCSCommitByHashRequest struct { 205 Hash string `json:"hash"` 206 IncludeChanges bool `json:"changes"` 207 } 208 209 // VCSCommitByHash request 210 func (sdk SDK) VCSCommitByHash(request VCSCommitByHashRequest) (*VCSCommit, error) { 211 resp, err := sdk.client.R(). 212 SetHeader("Accept", "application/json"). 213 SetResult(&VCSCommit{}). 214 SetError(&APIError{}). 215 Get(fmt.Sprintf("/vcs/commit/%s?changes=%s", request.Hash, strconv.FormatBool(request.IncludeChanges))) 216 217 if err != nil { 218 return nil, err 219 } else if resp.IsSuccess() { 220 return resp.Result().(*VCSCommit), nil 221 } else { 222 return nil, resp.Error().(*APIError) 223 } 224 } 225 226 // VCSTags request 227 func (sdk SDK) VCSTags() (*[]VCSTag, error) { 228 resp, err := sdk.client.R(). 229 SetHeader("Accept", "application/json"). 230 SetResult(&[]VCSTag{}). 231 SetError(&APIError{}). 232 Get("/vcs/tag") 233 234 if err != nil { 235 return nil, err 236 } else if resp.IsSuccess() { 237 return resp.Result().(*[]VCSTag), nil 238 } else { 239 return nil, resp.Error().(*APIError) 240 } 241 } 242 243 type VCSReleasesRequest struct { 244 Type string `json:"type"` // Type of the release: stable, unstable 245 } 246 247 // VCSReleases request 248 func (sdk SDK) VCSReleases(request VCSReleasesRequest) (*[]VCSRelease, error) { 249 resp, err := sdk.client.R(). 250 SetHeader("Accept", "application/json"). 251 SetResult(&[]VCSRelease{}). 252 SetError(&APIError{}). 253 Get(fmt.Sprintf("/vcs/release?type=%s", request.Type)) 254 255 if err != nil { 256 return nil, err 257 } else if resp.IsSuccess() { 258 return resp.Result().(*[]VCSRelease), nil 259 } else { 260 return nil, resp.Error().(*APIError) 261 } 262 } 263 264 type VCSDiffRequest struct { 265 FromHash string `json:"from"` 266 ToHash string `json:"to"` 267 } 268 269 // VCSDiff request 270 func (sdk SDK) VCSDiff(request VCSDiffRequest) (*[]VCSDiff, error) { 271 resp, err := sdk.client.R(). 272 SetHeader("Accept", "application/json"). 273 SetResult(&[]VCSDiff{}). 274 SetError(&APIError{}). 275 Get(fmt.Sprintf("/vcs/diff?from=%s&to=%s", request.FromHash, request.ToHash)) 276 277 if err != nil { 278 return nil, err 279 } else if resp.IsSuccess() { 280 return resp.Result().(*[]VCSDiff), nil 281 } else { 282 return nil, resp.Error().(*APIError) 283 } 284 } 285 286 type ArtifactListRequest struct { 287 Query string `json:"query"` 288 } 289 290 // ArtifactList request 291 func (sdk SDK) ArtifactList(request ArtifactListRequest) (*[]ActionArtifact, error) { 292 resp, err := sdk.client.R(). 293 SetHeader("Accept", "application/json"). 294 SetResult(&[]ActionArtifact{}). 295 SetError(&APIError{}). 296 Get(fmt.Sprintf("/artifact?query=%s", url.QueryEscape(request.Query))) 297 298 if err != nil { 299 return nil, err 300 } else if resp.IsSuccess() { 301 return resp.Result().(*[]ActionArtifact), nil 302 } else { 303 return nil, resp.Error().(*APIError) 304 } 305 } 306 307 type ArtifactUploadRequest struct { 308 File string `json:"file"` 309 Content string `json:"content"` 310 ContentBytes []byte `json:"content_bytes"` 311 Module string `json:"module"` 312 Type string `json:"type"` 313 Format string `json:"format"` 314 FormatVersion string `json:"format_version"` 315 ExtractFile bool `json:"extract_file"` 316 } 317 318 // ArtifactUpload request 319 func (sdk SDK) ArtifactUpload(request ArtifactUploadRequest) error { 320 // upload 321 payload := map[string]string{ 322 "type": request.Type, 323 "module": request.Module, 324 "format": request.Format, 325 "format_version": request.FormatVersion, 326 } 327 if request.ExtractFile { 328 payload["extract_file"] = "true" 329 } 330 331 if request.Content != "" || request.ContentBytes != nil { 332 var reader io.Reader 333 if request.Content != "" { 334 reader = strings.NewReader(request.Content) 335 } else { 336 reader = bytes.NewReader(request.ContentBytes) 337 } 338 339 resp, err := sdk.client.R(). 340 SetFormData(payload). 341 SetFileReader("file", request.File, reader). 342 SetContentLength(true). 343 SetError(&APIError{}). 344 Post("/artifact") 345 if err != nil { 346 return err 347 } else if resp.IsError() { 348 return resp.Error().(*APIError) 349 } 350 } else if request.File != "" { 351 resp, err := sdk.client.R(). 352 SetFormData(payload). 353 SetFile("file", request.File). 354 SetContentLength(true). 355 SetError(&APIError{}). 356 Post("/artifact") 357 if err != nil { 358 return err 359 } else if resp.IsError() { 360 return resp.Error().(*APIError) 361 } 362 } else { 363 return fmt.Errorf("file, content or contentBytes must be provided") 364 } 365 366 return nil 367 } 368 369 type ArtifactDownloadRequest struct { 370 ID string `json:"id"` 371 TargetFile string `json:"target_file"` 372 } 373 374 // ArtifactDownload request 375 func (sdk SDK) ArtifactDownload(request ArtifactDownloadRequest) error { 376 resp, err := sdk.client.R(). 377 SetQueryParam("id", request.ID). 378 SetOutput(request.TargetFile). 379 SetError(&APIError{}). 380 Get("/artifact/download") 381 if err != nil { 382 return err 383 } else if resp.IsError() { 384 return resp.Error().(*APIError) 385 } 386 387 return nil 388 } 389 390 type ArtifactDownloadByteArrayRequest struct { 391 ID string `json:"id"` 392 } 393 394 // ArtifactDownloadByteArray request 395 func (sdk SDK) ArtifactDownloadByteArray(request ArtifactDownloadByteArrayRequest) ([]byte, error) { 396 resp, err := sdk.client.R(). 397 SetQueryParam("id", request.ID). 398 SetError(&APIError{}). 399 Get("/artifact/download") 400 if err != nil { 401 return nil, err 402 } else if resp.IsError() { 403 return nil, resp.Error().(*APIError) 404 } 405 406 return resp.Body(), nil 407 }