golang.org/x/build@v0.0.0-20240506185731-218518f32b70/internal/macservice/client.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package macservice defines the client API for MacService. 6 package macservice 7 8 import ( 9 "bytes" 10 "encoding/json" 11 "fmt" 12 "io" 13 "net/http" 14 ) 15 16 const baseURL = "https://macservice-pa.googleapis.com/v1alpha1/" 17 18 // Client is a MacService client. 19 type Client struct { 20 apiKey string 21 22 client *http.Client 23 } 24 25 // NewClient creates a MacService client, authenticated with the provided API 26 // key. 27 func NewClient(apiKey string) *Client { 28 return &Client{ 29 apiKey: apiKey, 30 client: http.DefaultClient, 31 } 32 } 33 34 func (c *Client) do(method, endpoint string, input, output any) error { 35 var buf bytes.Buffer 36 enc := json.NewEncoder(&buf) 37 if err := enc.Encode(input); err != nil { 38 return fmt.Errorf("error encoding request: %w", err) 39 } 40 41 req, err := http.NewRequest(method, baseURL+endpoint, &buf) 42 if err != nil { 43 return fmt.Errorf("error building request: %w", err) 44 } 45 req.Header.Add("Content-Type", "application/json") 46 req.Header.Add("x-goog-api-key", c.apiKey) 47 48 resp, err := c.client.Do(req) 49 if err != nil { 50 return fmt.Errorf("error sending request: %w", err) 51 } 52 defer resp.Body.Close() 53 54 body, err := io.ReadAll(resp.Body) 55 if err != nil { 56 return fmt.Errorf("error reading response body: %w", err) 57 } 58 59 if resp.StatusCode != http.StatusOK { 60 return fmt.Errorf("response error %s: %s", resp.Status, body) 61 } 62 63 if err := json.Unmarshal(body, output); err != nil { 64 return fmt.Errorf("error decoding response: %w; body: %s", err, body) 65 } 66 67 return nil 68 } 69 70 // Lease creates a new lease. 71 func (c *Client) Lease(req LeaseRequest) (LeaseResponse, error) { 72 var resp LeaseResponse 73 if err := c.do("POST", "leases:create", req, &resp); err != nil { 74 return LeaseResponse{}, fmt.Errorf("error sending request: %w", err) 75 } 76 return resp, nil 77 } 78 79 // Renew updates the expiration time of a lease. Note that 80 // RenewRequest.Duration is the lease duration from now, not from the current 81 // lease expiration time. 82 func (c *Client) Renew(req RenewRequest) (RenewResponse, error) { 83 var resp RenewResponse 84 if err := c.do("POST", "leases:renew", req, &resp); err != nil { 85 return RenewResponse{}, fmt.Errorf("error sending request: %w", err) 86 } 87 return resp, nil 88 } 89 90 // Vacate vacates a lease. 91 func (c *Client) Vacate(req VacateRequest) error { 92 var resp struct{} // no response body 93 if err := c.do("POST", "leases:vacate", req, &resp); err != nil { 94 return fmt.Errorf("error sending request: %w", err) 95 } 96 return nil 97 } 98 99 // Find searches for leases. 100 func (c *Client) Find(req FindRequest) (FindResponse, error) { 101 var resp FindResponse 102 if err := c.do("POST", "leases:find", req, &resp); err != nil { 103 return FindResponse{}, fmt.Errorf("error sending request: %w", err) 104 } 105 return resp, nil 106 }