amo/api/api.go

163 lines
3 KiB
Go
Raw Normal View History

2024-01-15 00:04:00 +03:00
package api
import (
"net/url"
2024-03-04 04:31:33 +03:00
"time"
"log"
"os"
2024-01-15 00:04:00 +03:00
)
const (
2024-05-30 11:43:10 +03:00
DefaultContentType = "application/json"
DefaultAccept = DefaultContentType
2024-01-15 00:04:00 +03:00
DefaultCacheControl = "no-cache"
MaxEntitiesPerRequest = 250
2024-01-15 00:04:00 +03:00
)
type ClientOptions struct {
2024-05-30 11:43:10 +03:00
URL string `json:"url"`
RedirectURL string `json:"redirect_url"`
2024-01-15 03:48:01 +03:00
AuthCode string `json:"auth_code"`
2024-01-15 03:48:01 +03:00
2024-05-30 11:43:10 +03:00
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
2024-01-15 03:48:01 +03:00
2024-05-30 11:43:10 +03:00
AccessToken string `json:"access_token"`
ExpirationAt time.Time `json:"expiration_at,omitempty"`
RefreshToken string `json:"refresh_token"`
2024-01-15 00:04:00 +03:00
}
type Client struct {
2024-03-04 04:31:33 +03:00
*log.Logger
2024-05-30 11:43:10 +03:00
options ClientOptions
BaseURL *url.URL
secretStoreFilePath string
2024-03-04 04:31:33 +03:00
Debug bool
availableRequests int
mrps int
ticker *time.Ticker
2024-05-31 20:19:41 +03:00
req, reqNeed chan struct{}
requestsMade int64
2024-01-15 00:04:00 +03:00
}
2024-05-30 11:43:10 +03:00
type OAuthTokenResponse struct {
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
AccessToken string `json:"access_token"`
2024-01-15 00:04:00 +03:00
RefreshToken string `json:"refresh_token"`
}
2024-01-15 03:48:01 +03:00
type TokenPair struct {
Access, Refresh string
}
2024-01-15 00:04:00 +03:00
2024-05-30 11:43:10 +03:00
func NewAPI(secretPath string) (*Client, error) {
2024-03-04 04:31:33 +03:00
client := &Client{
2024-05-30 11:43:10 +03:00
Logger: log.New(
os.Stdout,
"AmoCRM client: ",
log.Ldate | log.Ltime,
),
secretStoreFilePath: secretPath,
2024-01-15 03:48:01 +03:00
}
2024-03-04 04:31:33 +03:00
options, err := client.readSecret()
2024-01-15 00:04:00 +03:00
if err != nil {
2024-05-30 11:43:10 +03:00
return nil, NewErrorAPI(err)
2024-03-04 04:31:33 +03:00
}
if client.Debug {
client.Printf("ClientOptions: %v\n", options)
2024-01-15 03:48:01 +03:00
}
2024-05-30 11:43:10 +03:00
if options.URL == "" || options.RedirectURL == "" {
return nil, NewErrorAPI(ErrInvalidOptionsURL)
2024-01-15 03:48:01 +03:00
}
2024-03-04 04:31:33 +03:00
2024-05-30 11:43:10 +03:00
parsedURL, err := url.Parse(options.URL)
if err != nil {
2024-05-30 11:43:10 +03:00
return nil, NewErrorAPI(err)
}
2024-05-30 11:43:10 +03:00
client.BaseURL = parsedURL
2024-03-04 04:31:33 +03:00
client.options = options
var (
//pair *TokenPair
exchangeErr error
exchanged bool
)
2024-05-30 11:43:10 +03:00
if client.options.AccessToken == "" &&
client.options.RefreshToken == "" {
2024-03-04 04:31:33 +03:00
if client.options.ClientSecret == "" ||
client.options.ClientId == "" ||
client.options.AuthCode == "" {
2024-05-30 11:43:10 +03:00
return nil, NewErrorAPI(
ErrInvalidExchangeAuthOptions,
)
2024-01-15 03:48:01 +03:00
}
2024-05-30 11:43:10 +03:00
2024-03-04 04:31:33 +03:00
_, exchangeErr = client.ExchangeAuth()
exchanged = true
2024-01-15 00:04:00 +03:00
}
2024-05-30 11:43:10 +03:00
if (!exchanged || exchangeErr != nil) &&
options.RefreshToken != "" {
// Refreshing token before the work.
// Should think of how often should refresh
// the token. (see the ExpiresIn)
2024-03-04 04:31:33 +03:00
_, err = client.RefreshToken()
if err != nil {
2024-05-30 11:43:10 +03:00
return nil, NewErrorAPI(err)
}
}
2024-01-15 03:48:01 +03:00
2024-03-04 04:31:33 +03:00
return client, nil
2024-01-15 00:04:00 +03:00
}
// Set maximum requests per second.
func (client *Client) SetMRPS(rps int) *Client {
client.mrps = rps
client.req = make(chan struct{})
2024-05-31 20:19:41 +03:00
client.reqNeed = make(chan struct{})
client.ticker = time.NewTicker(
time.Second/time.Duration(rps),
)
go func() {
for {
2024-05-31 20:19:41 +03:00
select {
case <- client.reqNeed :
client.req <- struct{}{}
}
<-client.ticker.C
}
}()
return client
}
func (client *Client) waitInQueue() bool {
// Just leaving if MRPS is not set.
if client.mrps == 0 {
return false
}
2024-05-31 20:19:41 +03:00
client.reqNeed <- struct{}{}
<- client.req
return true
}
func (client *Client) finishRequest() {
}
func (client *Client) RequestsMade() int64 {
return client.requestsMade
}