diff --git a/go-workspace/src/garage/admin_client.go b/go-workspace/src/garage/admin_client.go new file mode 100644 index 0000000..1ff6e15 --- /dev/null +++ b/go-workspace/src/garage/admin_client.go @@ -0,0 +1,84 @@ +package garage + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" +) + +// AdminClient is a helper type for performing actions against the garage admin +// interface. +type AdminClient struct { + c *http.Client + addr string + adminToken string +} + +// NewAdminClient initializes and returns an AdminClient which will use the +// given address and adminToken for all requests made. +func NewAdminClient(addr, adminToken string) *AdminClient { + return &AdminClient{ + c: &http.Client{ + Transport: http.DefaultTransport.(*http.Transport).Clone(), + }, + addr: addr, + adminToken: adminToken, + } +} + +// Do performs an HTTP request with the given method (GET, POST) and path, and +// using the json marshaling of the given body as the request body (unless body +// is nil). It will JSON unmarshal the response into rcv, unless rcv is nil. +func (c *AdminClient) Do( + ctx context.Context, rcv interface{}, method, path string, body interface{}, +) error { + + var bodyR io.Reader + + if body != nil { + bodyBuf := new(bytes.Buffer) + bodyR = bodyBuf + + if err := json.NewEncoder(bodyBuf).Encode(body); err != nil { + return fmt.Errorf("json marshaling body: %w", err) + } + } + + urlStr := fmt.Sprintf("http://%s%s", c.addr, path) + + req, err := http.NewRequestWithContext(ctx, method, urlStr, bodyR) + if err != nil { + return fmt.Errorf("initializing request: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+c.adminToken) + + res, err := c.c.Do(req) + if err != nil { + return fmt.Errorf("performing http request: %w", err) + } + + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("unexpected %s response returned", res.Status) + } + + if rcv == nil { + + if _, err := io.Copy(io.Discard, res.Body); err != nil { + return fmt.Errorf("discarding response body: %w", err) + } + + return nil + } + + if err := json.NewDecoder(res.Body).Decode(rcv); err != nil { + return fmt.Errorf("decoding json response body: %w", err) + } + + return nil +}