fix: better errors.

This commit is contained in:
Andrey Parhomenko 2024-03-04 06:31:33 +05:00
parent ebd4866455
commit 28f6a7e2ec
3 changed files with 63 additions and 43 deletions

View file

@ -2,6 +2,8 @@ package amo
import ( import (
"fmt" "fmt"
"time"
"errors"
"vultras.su/core/amo/api" "vultras.su/core/amo/api"
"vultras.su/core/amo/companies" "vultras.su/core/amo/companies"
"vultras.su/core/amo/contacts" "vultras.su/core/amo/contacts"
@ -92,7 +94,8 @@ func (client *Client) GetEvents(req events.EventsRequest) ([]events.Event, error
resp := events.EventsResponse{} resp := events.EventsResponse{}
err := client.Api.Get(res, &resp, abs) err := client.Api.Get(res, &resp, abs)
if err != nil { if err != nil {
if err == api.NoContentErr { // Return empty if no content avialable.
if errors.Is(err, api.NoContentErr) {
return ret, nil return ret, nil
} }
return nil, err return nil, err
@ -101,6 +104,7 @@ func (client *Client) GetEvents(req events.EventsRequest) ([]events.Event, error
if resp.Links.Next.Href == "" { if resp.Links.Next.Href == "" {
break break
} }
time.Sleep(time.Millisecond*300)
abs = true abs = true
res = resp.Links.Next.Href res = resp.Links.Next.Href
} }

View file

@ -1,16 +1,17 @@
package api package api
import ( import (
"bytes"
"encoding/json" "encoding/json"
"errors"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"errors"
"bytes"
"time"
"fmt"
"log"
"io" "io"
"os" "os"
"time"
) )
const ( const (
@ -35,10 +36,11 @@ type ClientOptions struct {
} }
type Client struct { type Client struct {
*log.Logger
options *ClientOptions options *ClientOptions
BaseUrl *url.URL BaseUrl *url.URL
secretStoreFilePath string secretStoreFilePath string
Debug bool `json` Debug bool
} }
type requestOptions struct { type requestOptions struct {
@ -60,42 +62,43 @@ type TokenPair struct {
} }
func NewApi(secretPath string) (*Client, error) { func NewApi(secretPath string) (*Client, error) {
ret := &Client{ client := &Client{
Logger: log.New(os.Stdout, "AmoCRM client: ", log.Ldate | log.Ltime),
secretStoreFilePath: secretPath, secretStoreFilePath: secretPath,
} }
options, err := ret.readSecret() options, err := client.readSecret()
if err != nil { if err != nil {
return nil, err return nil, NewApiError(err)
}
if client.Debug {
client.Printf("ClientOptions: %v\n", options)
} }
fmt.Println("opts:", options)
if options.Url == "" || options.RedirectUrl == "" { if options.Url == "" || options.RedirectUrl == "" {
return nil, errors.New("AmoCrm: Invalid options: Url") return nil, NewApiError(InvalidUrlOptionsErr)
} }
resolvedUrl, err := url.Parse(options.Url) resolvedUrl, err := url.Parse(options.Url)
if err != nil { if err != nil {
return nil, err return nil, NewApiError(err)
} }
ret.BaseUrl = resolvedUrl client.BaseUrl = resolvedUrl
client.options = options
if err != nil {
return nil, err
}
ret.options = options
var ( var (
//pair *TokenPair //pair *TokenPair
exchangeErr error exchangeErr error
exchanged bool exchanged bool
) )
if ret.options.AccessToken == "" && ret.options.RefreshToken == "" { if client.options.AccessToken == "" && client.options.RefreshToken == "" {
if ret.options.ClientSecret == "" || if client.options.ClientSecret == "" ||
ret.options.ClientId == "" || client.options.ClientId == "" ||
ret.options.AuthCode == "" { client.options.AuthCode == "" {
return nil, errors.New("AmoCrm: invalid options: ExchangeAuth") return nil, NewApiError(InvalidExchangeAuthOptionsErr)
} }
_, exchangeErr = ret.ExchangeAuth() _, exchangeErr = client.ExchangeAuth()
exchanged = true exchanged = true
} }
@ -103,16 +106,13 @@ func NewApi(secretPath string) (*Client, error) {
// Refreshing token before the work. // Refreshing token before the work.
// Should think of how often should refresh // Should think of how often should refresh
// the token. (see the ExpiresIn) // the token. (see the ExpiresIn)
_, err = ret.RefreshToken() _, err = client.RefreshToken()
if err != nil { if err != nil {
return nil, err return nil, NewApiError(err)
} }
} }
return &Client{ return client, nil
options: options,
BaseUrl: resolvedUrl,
}, nil
} }
func (api *Client) readSecret() (*ClientOptions, error) { func (api *Client) readSecret() (*ClientOptions, error) {
@ -190,37 +190,40 @@ func (api *Client) rdoRequest(resourceUrl string, requestParams requestOptions,
response, err := http.DefaultClient.Do(request) response, err := http.DefaultClient.Do(request)
if api.Debug { if api.Debug {
fmt.Printf("\nAmo request: %+v\nAmo repsonse: %+v\n", request, response) api.Printf("Request: %+v\n\nAmo response: %+v\n\n", request, response)
} }
if response == nil { if response == nil {
return NoInternetErr return RequestError(NoInternetErr)
} }
if err != nil { if err != nil {
return errors.New(fmt.Sprintf( return RequestError(fmt.Errorf(
"Request error: %s %d %s %s", "%w: %d %s %s",
err.Error(), err,
response.StatusCode, response.StatusCode,
requestParams.HttpMethod, requestParams.HttpMethod,
resourceUrl, resourceUrl,
)) ))
} }
defer response.Body.Close() defer response.Body.Close()
if response.StatusCode == 204 { if response.StatusCode == 204 {
return NoContentErr return RequestError(NoContentErr)
} }
if response.StatusCode >= 400 { if response.StatusCode >= 400 {
var specErr error
if response.StatusCode == 401 { if response.StatusCode == 401 {
return NoAuthErr specErr = NoAuthErr
} }
bodyBytes, _ := ioutil.ReadAll(response.Body) responseErrorInfo, _ := ioutil.ReadAll(response.Body)
return errors.New(fmt.Sprintf( return RequestError(fmt.Errorf(
"%s %d %s %s", "%w: %s %s %q %d",
string(bodyBytes), specErr,
response.StatusCode,
requestParams.HttpMethod, requestParams.HttpMethod,
resourceUrl, resourceUrl,
string(responseErrorInfo),
response.StatusCode,
)) ))
} }
@ -239,7 +242,7 @@ func (api *Client) doRequest(
) error { ) error {
var err error var err error
err = api.rdoRequest(resourceUrl, requestParams, result) err = api.rdoRequest(resourceUrl, requestParams, result)
if err == NoAuthErr && api.options.RefreshToken != "" { if errors.Is(err, NoAuthErr) && api.options.RefreshToken != "" {
_, err = api.RefreshToken() _, err = api.RefreshToken()
if err != nil { if err != nil {
return nil return nil

View file

@ -2,10 +2,23 @@ package api
import ( import (
"errors" "errors"
"fmt"
) )
var ( var (
NoContentErr = errors.New("no content") NoContentErr = errors.New("no content")
NoAuthErr = errors.New("not authorized") NoAuthErr = errors.New("not authorized")
NoInternetErr = errors.New("no Internet provided") NoInternetErr = errors.New("no Internet provided")
InvalidUrlOptionsErr = errors.New("invalid URL options")
InvalidExchangeAuthOptionsErr = errors.New("invalid ExchangeAuth options")
UrlParsingErr = errors.New("URL parsing")
) )
func NewApiError(err error) error {
return fmt.Errorf("NewApi: %w", err)
}
func RequestError(err error) error {
return fmt.Errorf("RequestError: %w", err)
}