mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-06 00:01:24 +00:00
88 lines
2.3 KiB
Go
88 lines
2.3 KiB
Go
package cloudlink
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
)
|
|
|
|
// client is the outbound-only HTTP client to the cloud's pool-link API.
|
|
type client struct {
|
|
baseURL string
|
|
token string
|
|
version string
|
|
http *http.Client
|
|
}
|
|
|
|
func newClient(baseURL, token, version string) *client {
|
|
return &client{
|
|
baseURL: strings.TrimRight(strings.TrimSpace(baseURL), "/"),
|
|
token: token,
|
|
version: version,
|
|
http: &http.Client{Timeout: 20 * time.Second},
|
|
}
|
|
}
|
|
|
|
// remoteError is the cloud's error envelope, re-surfaced with its own code.
|
|
type remoteError struct {
|
|
Error string `json:"error"`
|
|
Message string `json:"message"`
|
|
Code string `json:"code"`
|
|
RequestID string `json:"request_id"`
|
|
}
|
|
|
|
func (c *client) do(ctx context.Context, method, path string, body any, out any) *errx.Error {
|
|
var buf io.Reader
|
|
if body != nil {
|
|
raw, err := json.Marshal(body)
|
|
if err != nil {
|
|
return errx.InternalError()
|
|
}
|
|
buf = bytes.NewReader(raw)
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, method, c.baseURL+"/v1/pool-link"+path, buf)
|
|
if err != nil {
|
|
return errx.InternalError()
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Accept", "application/json")
|
|
req.Header.Set("User-Agent", "warmbly-cloudlink/"+c.version)
|
|
if c.token != "" {
|
|
req.Header.Set("Authorization", "Bearer "+c.token)
|
|
}
|
|
if c.version != "" {
|
|
req.Header.Set("X-Warmbly-Instance-Version", c.version)
|
|
}
|
|
res, err := c.http.Do(req)
|
|
if err != nil {
|
|
return errx.NewWithIdentifier(errx.ServiceUnavailable, "cloud_link_unreachable", fmt.Sprintf("Warmbly Cloud could not be reached: %v", err))
|
|
}
|
|
defer res.Body.Close()
|
|
raw, _ := io.ReadAll(io.LimitReader(res.Body, 4<<20))
|
|
if res.StatusCode >= 400 {
|
|
var re remoteError
|
|
_ = json.Unmarshal(raw, &re)
|
|
code := errx.Code(res.StatusCode)
|
|
if re.Message == "" {
|
|
re.Message = fmt.Sprintf("Warmbly Cloud answered %d", res.StatusCode)
|
|
}
|
|
if re.Code == "" {
|
|
re.Code = "cloud_link_remote"
|
|
}
|
|
return errx.NewWithIdentifier(code, re.Code, re.Message)
|
|
}
|
|
if out != nil && len(raw) > 0 {
|
|
if err := json.Unmarshal(raw, out); err != nil {
|
|
return errx.NewWithIdentifier(errx.ServiceUnavailable, "cloud_link_bad_response", "Warmbly Cloud returned an unreadable response.")
|
|
}
|
|
}
|
|
return nil
|
|
}
|