amo/api/request.go

169 lines
2.6 KiB
Go

package api
import "encoding/json"
import "net/http"
import "net/url"
import "errors"
import "bytes"
import "fmt"
import "io"
type RequestOptions struct {
Method string
Body interface{}
Headers map[string]string
}
func (client *Client) doRawRequest(
u *url.URL,
params RequestOptions,
result interface{},
) error {
var (
err error
)
client.requestsMade++
reqBody := new(bytes.Buffer)
if params.Body != nil {
encoder := json.NewEncoder(reqBody)
err := encoder.Encode(params.Body)
if err != nil {
return err
}
}
request, err := http.NewRequest(
params.Method,
u.String(),
reqBody,
)
if err != nil {
return err
}
if params.Headers != nil {
for k, v := range params.Headers {
request.Header.Set(k, v)
}
}
res, err := http.DefaultClient.Do(request)
if client.Debug {
client.Printf(
"Request: %+v\n\nAmo response: %+v\n\n",
request,
res,
)
}
if res == nil {
if err != nil {
return NewRequestError(err)
}
return NewRequestError(ErrUnreachable)
}
if err != nil {
return NewRequestError(fmt.Errorf(
"%w: %d %s %s",
err,
res.StatusCode,
params.Method,
u,
))
}
defer res.Body.Close()
if res.StatusCode == 204 {
return NewRequestError(ErrNoContent)
}
if res.StatusCode >= 400 {
var specErr error
if res.StatusCode == 401 {
specErr = ErrNoAuth
}
resErrInfo, _ := io.ReadAll(res.Body)
return NewRequestError(fmt.Errorf(
"%w: %s %s %q %d",
specErr,
params.Method,
u,
string(resErrInfo),
res.StatusCode,
))
}
if result != nil {
decoder := json.NewDecoder(res.Body)
err = decoder.Decode(result)
if err != nil {
return err
}
}
return nil
}
func (client *Client) doRequest(
u string,
params RequestOptions,
result any,
) error {
var (
err error
parsedURL *url.URL
)
if client.waitInQueue() {
defer client.finishRequest()
}
parsedURL, err = url.Parse(u)
if err != nil {
return err
}
reqURL := client.BaseURL.ResolveReference(parsedURL)
err = client.doRawRequest(
reqURL,
params,
result,
)
if errors.Is(err, ErrNoAuth) &&
client.options.RefreshToken != "" {
_, err = client.RefreshToken()
if err != nil {
return nil
}
return client.doRawRequest(
reqURL,
params,
result,
)
} else if err != nil {
return err
}
return nil
}
func makeHeaders(
token string,
) map[string]string {
headers := map[string]string{
"Accept": DefaultAccept,
"Cache-Control": DefaultCacheControl,
"Content-Type": DefaultContentType,
}
if len(token) > 0 {
headers["Authorization"] =
fmt.Sprintf("Bearer %s", token)
}
return headers
}