From 28f6a7e2ec978777649cfa824a3e2f726ff5dd71 Mon Sep 17 00:00:00 2001 From: surdeus Date: Mon, 4 Mar 2024 06:31:33 +0500 Subject: [PATCH] fix: better errors. --- amocrm.go | 6 +++- api/api.go | 87 ++++++++++++++++++++++++++------------------------- api/errors.go | 13 ++++++++ 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/amocrm.go b/amocrm.go index 82c8556..085fca9 100644 --- a/amocrm.go +++ b/amocrm.go @@ -2,6 +2,8 @@ package amo import ( "fmt" + "time" + "errors" "vultras.su/core/amo/api" "vultras.su/core/amo/companies" "vultras.su/core/amo/contacts" @@ -92,7 +94,8 @@ func (client *Client) GetEvents(req events.EventsRequest) ([]events.Event, error resp := events.EventsResponse{} err := client.Api.Get(res, &resp, abs) if err != nil { - if err == api.NoContentErr { + // Return empty if no content avialable. + if errors.Is(err, api.NoContentErr) { return ret, nil } return nil, err @@ -101,6 +104,7 @@ func (client *Client) GetEvents(req events.EventsRequest) ([]events.Event, error if resp.Links.Next.Href == "" { break } + time.Sleep(time.Millisecond*300) abs = true res = resp.Links.Next.Href } diff --git a/api/api.go b/api/api.go index 1a47968..80fb1f8 100644 --- a/api/api.go +++ b/api/api.go @@ -1,16 +1,17 @@ package api import ( - "bytes" "encoding/json" - "errors" - "fmt" "io/ioutil" "net/http" "net/url" + "errors" + "bytes" + "time" + "fmt" + "log" "io" "os" - "time" ) const ( @@ -35,10 +36,11 @@ type ClientOptions struct { } type Client struct { + *log.Logger options *ClientOptions BaseUrl *url.URL secretStoreFilePath string - Debug bool `json` + Debug bool } type requestOptions struct { @@ -60,42 +62,43 @@ type TokenPair struct { } func NewApi(secretPath string) (*Client, error) { - ret := &Client{ + client := &Client{ + Logger: log.New(os.Stdout, "AmoCRM client: ", log.Ldate | log.Ltime), secretStoreFilePath: secretPath, } - options, err := ret.readSecret() + options, err := client.readSecret() 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 == "" { - return nil, errors.New("AmoCrm: Invalid options: Url") + return nil, NewApiError(InvalidUrlOptionsErr) } + resolvedUrl, err := url.Parse(options.Url) if err != nil { - return nil, err + return nil, NewApiError(err) } - ret.BaseUrl = resolvedUrl - - if err != nil { - return nil, err - } - ret.options = options + client.BaseUrl = resolvedUrl + client.options = options var ( //pair *TokenPair exchangeErr error exchanged bool ) - if ret.options.AccessToken == "" && ret.options.RefreshToken == "" { - if ret.options.ClientSecret == "" || - ret.options.ClientId == "" || - ret.options.AuthCode == "" { - return nil, errors.New("AmoCrm: invalid options: ExchangeAuth") + if client.options.AccessToken == "" && client.options.RefreshToken == "" { + if client.options.ClientSecret == "" || + client.options.ClientId == "" || + client.options.AuthCode == "" { + return nil, NewApiError(InvalidExchangeAuthOptionsErr) } - _, exchangeErr = ret.ExchangeAuth() + _, exchangeErr = client.ExchangeAuth() exchanged = true } @@ -103,16 +106,13 @@ func NewApi(secretPath string) (*Client, error) { // Refreshing token before the work. // Should think of how often should refresh // the token. (see the ExpiresIn) - _, err = ret.RefreshToken() + _, err = client.RefreshToken() if err != nil { - return nil, err + return nil, NewApiError(err) } } - return &Client{ - options: options, - BaseUrl: resolvedUrl, - }, nil + return client, nil } func (api *Client) readSecret() (*ClientOptions, error) { @@ -190,37 +190,40 @@ func (api *Client) rdoRequest(resourceUrl string, requestParams requestOptions, response, err := http.DefaultClient.Do(request) 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 { - return NoInternetErr + return RequestError(NoInternetErr) } if err != nil { - return errors.New(fmt.Sprintf( - "Request error: %s %d %s %s", - err.Error(), + return RequestError(fmt.Errorf( + "%w: %d %s %s", + err, response.StatusCode, requestParams.HttpMethod, resourceUrl, )) } defer response.Body.Close() + if response.StatusCode == 204 { - return NoContentErr + return RequestError(NoContentErr) } if response.StatusCode >= 400 { + var specErr error if response.StatusCode == 401 { - return NoAuthErr + specErr = NoAuthErr } - bodyBytes, _ := ioutil.ReadAll(response.Body) - return errors.New(fmt.Sprintf( - "%s %d %s %s", - string(bodyBytes), - response.StatusCode, + responseErrorInfo, _ := ioutil.ReadAll(response.Body) + return RequestError(fmt.Errorf( + "%w: %s %s %q %d", + specErr, requestParams.HttpMethod, resourceUrl, + string(responseErrorInfo), + response.StatusCode, )) } @@ -239,7 +242,7 @@ func (api *Client) doRequest( ) error { var err error err = api.rdoRequest(resourceUrl, requestParams, result) - if err == NoAuthErr && api.options.RefreshToken != "" { + if errors.Is(err, NoAuthErr) && api.options.RefreshToken != "" { _, err = api.RefreshToken() if err != nil { return nil diff --git a/api/errors.go b/api/errors.go index 13c48d1..d5dfc32 100644 --- a/api/errors.go +++ b/api/errors.go @@ -2,10 +2,23 @@ package api import ( "errors" + "fmt" ) var ( NoContentErr = errors.New("no content") NoAuthErr = errors.New("not authorized") 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) +} +