exportarr/internal/client/client.go
Jack b8b7cc6be3
Feature/support bazarr (#214)
* remove the branch requirement to run tests

feature/support-bazarr

* lint makefile

feature/support-bazarr

* add bazarr to readme

feature/support-bazarr

* also comment out release image as we only want tests to happen

feature/support-bazarr

* initial changes to start attempting to pull bazarr i thinnk?

feature/support-bazarr

* make it only run the tests, but skip release image

feature/support-bazarr

* add a genric makefile to build container localy, run and test

feature/support-bazarr

* rename build command

feature/support-bazarr

* add pic and grafana dashboard adjustments

feature/support-bazarr

* refactor metrics to just be contained within 1 class

* add logic to allow csv values to params

* remove some todos

* make api version optional

feature/support-bazarr

* adjust makefile to auto kill and start

feature/support-bazarr

* remove now invalid test

feature/support-bazarr

* add a test for no api version instead

feature/support-bazarr

* add a test to enforce csv params moving forward

feature/support-bazarr

* add saml payloads for all endpoints, add test that mocks and verifies result

feature/support-bazarr

* Update .env.dist

* Update .gitignore

* Update internal/client/client.go

* add a tidy task

---------

Co-authored-by: Devin Buhl <onedr0p@users.noreply.github.com>
2023-10-08 02:32:59 -04:00

98 lines
2.4 KiB
Go

package client
import (
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"go.uber.org/zap"
)
// Client struct is an *Arr client.
type Client struct {
httpClient http.Client
URL url.URL
}
// NewClient method initializes a new *Arr client.
func NewClient(baseURL string, insecureSkipVerify bool, auth Authenticator) (*Client, error) {
u, err := url.Parse(baseURL)
if err != nil {
return nil, fmt.Errorf("Failed to parse URL(%s): %w", baseURL, err)
}
return &Client{
httpClient: http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: NewExportarrTransport(BaseTransport(insecureSkipVerify), auth),
},
URL: *u,
}, nil
}
func (c *Client) unmarshalBody(b io.Reader, target interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
// return recovered panic as error
err = fmt.Errorf("Recovered from panic: %s", r)
log := zap.S()
if zap.S().Level() == zap.DebugLevel {
s := new(strings.Builder)
_, copyErr := io.Copy(s, b)
if copyErr != nil {
zap.S().Errorw("Failed to copy body to string in recover",
"error", err, "recover", r)
}
log = log.With("body", s.String())
}
log.Errorw("Recovered while unmarshalling response", "error", r)
}
}()
err = json.NewDecoder(b).Decode(target)
return
}
// DoRequest - Take a HTTP Request and return Unmarshaled data
func (c *Client) DoRequest(endpoint string, target interface{}, queryParams ...map[string]string) error {
values := c.URL.Query()
for _, m := range queryParams {
for k, v := range m {
for _, j := range strings.Split(v, ",") {
values.Add(k, j)
}
}
}
url := c.URL.JoinPath(endpoint)
url.RawQuery = values.Encode()
zap.S().Infow("Sending HTTP request",
"url", url)
req, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
return fmt.Errorf("Failed to create HTTP Request(%s): %w", url, err)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("Failed to execute HTTP Request(%s): %w", url, err)
}
defer resp.Body.Close()
return c.unmarshalBody(resp.Body, target)
}
func BaseTransport(insecureSkipVerify bool) http.RoundTripper {
baseTransport := http.DefaultTransport
if insecureSkipVerify {
baseTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
return baseTransport
}