api.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package api
  2. import (
  3. "net/url"
  4. "time"
  5. "log"
  6. "os"
  7. )
  8. const (
  9. DefaultContentType = "application/json"
  10. DefaultAccept = DefaultContentType
  11. DefaultCacheControl = "no-cache"
  12. MaxEntitiesPerRequest = 250
  13. )
  14. type ClientOptions struct {
  15. URL string `json:"url"`
  16. RedirectURL string `json:"redirect_url"`
  17. AuthCode string `json:"auth_code"`
  18. ClientId string `json:"client_id"`
  19. ClientSecret string `json:"client_secret"`
  20. AccessToken string `json:"access_token"`
  21. ExpirationAt time.Time `json:"expiration_at,omitempty"`
  22. RefreshToken string `json:"refresh_token"`
  23. }
  24. type Client struct {
  25. *log.Logger
  26. options ClientOptions
  27. BaseURL *url.URL
  28. secretStoreFilePath string
  29. Debug bool
  30. availableRequests int
  31. mrps int
  32. ticker *time.Ticker
  33. req, reqNeed chan struct{}
  34. requestsMade int64
  35. }
  36. type OAuthTokenResponse struct {
  37. TokenType string `json:"token_type"`
  38. ExpiresIn int `json:"expires_in"`
  39. AccessToken string `json:"access_token"`
  40. RefreshToken string `json:"refresh_token"`
  41. }
  42. type TokenPair struct {
  43. Access, Refresh string
  44. }
  45. func NewAPI(secretPath string) (*Client, error) {
  46. client := &Client{
  47. Logger: log.New(
  48. os.Stdout,
  49. "AmoCRM client: ",
  50. log.Ldate | log.Ltime,
  51. ),
  52. secretStoreFilePath: secretPath,
  53. }
  54. options, err := client.readSecret()
  55. if err != nil {
  56. return nil, NewErrorAPI(err)
  57. }
  58. if client.Debug {
  59. client.Printf("ClientOptions: %v\n", options)
  60. }
  61. if options.URL == "" || options.RedirectURL == "" {
  62. return nil, NewErrorAPI(ErrInvalidOptionsURL)
  63. }
  64. parsedURL, err := url.Parse(options.URL)
  65. if err != nil {
  66. return nil, NewErrorAPI(err)
  67. }
  68. client.BaseURL = parsedURL
  69. client.options = options
  70. var (
  71. //pair *TokenPair
  72. exchangeErr error
  73. exchanged bool
  74. )
  75. if client.options.AccessToken == "" &&
  76. client.options.RefreshToken == "" {
  77. if client.options.ClientSecret == "" ||
  78. client.options.ClientId == "" ||
  79. client.options.AuthCode == "" {
  80. return nil, NewErrorAPI(
  81. ErrInvalidExchangeAuthOptions,
  82. )
  83. }
  84. _, exchangeErr = client.ExchangeAuth()
  85. exchanged = true
  86. }
  87. if (!exchanged || exchangeErr != nil) &&
  88. options.RefreshToken != "" {
  89. // Refreshing token before the work.
  90. // Should think of how often should refresh
  91. // the token. (see the ExpiresIn)
  92. _, err = client.RefreshToken()
  93. if err != nil {
  94. return nil, NewErrorAPI(err)
  95. }
  96. }
  97. return client, nil
  98. }
  99. // Set maximum requests per second.
  100. func (client *Client) SetMRPS(rps int) *Client {
  101. client.mrps = rps
  102. client.req = make(chan struct{})
  103. client.reqNeed = make(chan struct{})
  104. client.ticker = time.NewTicker(
  105. time.Second/time.Duration(rps),
  106. )
  107. go func() {
  108. for {
  109. select {
  110. case <- client.reqNeed :
  111. client.req <- struct{}{}
  112. }
  113. <-client.ticker.C
  114. }
  115. }()
  116. return client
  117. }
  118. func (client *Client) waitInQueue() bool {
  119. // Just leaving if MRPS is not set.
  120. if client.mrps == 0 {
  121. return false
  122. }
  123. client.reqNeed <- struct{}{}
  124. <- client.req
  125. return true
  126. }
  127. func (client *Client) finishRequest() {
  128. }
  129. func (client *Client) RequestsMade() int64 {
  130. return client.requestsMade
  131. }