Files
coder/codersdk/client.go
Kyle Carberry 2654a93132 chore: Fix golangci-lint configuration and patch errors (#34)
* chore: Fix golangci-lint configuration and patch errors

Due to misconfiguration of a linting rules directory, our linter has not been
working properly. This change fixes the configuration issue, and all remaining
linting errors.

* Fix race in peer logging

* Fix race and return

* Lock on bufferred amount low

* Fix mutex lock
2022-01-20 10:00:13 -06:00

117 lines
2.5 KiB
Go

package codersdk
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/http/cookiejar"
"net/url"
"golang.org/x/xerrors"
"github.com/coder/coder/httpapi"
"github.com/coder/coder/httpmw"
)
// New creates a Coder client for the provided URL.
func New(serverURL *url.URL) *Client {
return &Client{
url: serverURL,
httpClient: &http.Client{},
}
}
// Client is an HTTP caller for methods to the Coder API.
type Client struct {
url *url.URL
httpClient *http.Client
}
// SetSessionToken applies the provided token to the current client.
func (c *Client) SetSessionToken(token string) error {
if c.httpClient.Jar == nil {
var err error
c.httpClient.Jar, err = cookiejar.New(nil)
if err != nil {
return err
}
}
c.httpClient.Jar.SetCookies(c.url, []*http.Cookie{{
Name: httpmw.AuthCookie,
Value: token,
}})
return nil
}
// request performs an HTTP request with the body provided.
// The caller is responsible for closing the response body.
func (c *Client) request(ctx context.Context, method, path string, body interface{}) (*http.Response, error) {
serverURL, err := c.url.Parse(path)
if err != nil {
return nil, xerrors.Errorf("parse url: %w", err)
}
var buf bytes.Buffer
if body != nil {
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
err = enc.Encode(body)
if err != nil {
return nil, xerrors.Errorf("encode body: %w", err)
}
}
req, err := http.NewRequestWithContext(ctx, method, serverURL.String(), &buf)
if err != nil {
return nil, xerrors.Errorf("create request: %w", err)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, xerrors.Errorf("do: %w", err)
}
return resp, err
}
// readBodyAsError reads the response as an httpapi.Message, and
// wraps it in a codersdk.Error type for easy marshaling.
func readBodyAsError(res *http.Response) error {
var m httpapi.Response
err := json.NewDecoder(res.Body).Decode(&m)
if err != nil {
if errors.Is(err, io.EOF) {
// If no body is sent, we'll just provide the status code.
return &Error{
statusCode: res.StatusCode,
}
}
return xerrors.Errorf("decode body: %w", err)
}
return &Error{
Response: m,
statusCode: res.StatusCode,
}
}
// Error represents an unaccepted or invalid request to the API.
type Error struct {
httpapi.Response
statusCode int
}
func (e *Error) StatusCode() int {
return e.statusCode
}
func (e *Error) Error() string {
return fmt.Sprintf("status code %d: %s", e.statusCode, e.Message)
}