77 "fmt"
88 "io"
99 "net/http"
10+ "strconv"
1011 "strings"
1112 "time"
1213
@@ -21,9 +22,10 @@ const (
2122type Client struct {
2223 client * http.Client
2324
24- BaseURL string
25- Token string
26- RateLimiter * rate.Limiter
25+ BaseURL string
26+ Token string
27+ ReadRateLimiter * rate.Limiter
28+ UpdateRateLimiter * rate.Limiter
2729
2830 UserAgent string
2931
@@ -115,11 +117,12 @@ func NewClient(baseURL, clientID, clientSecret string) (*Client, error) {
115117 }
116118
117119 c := & Client {
118- client : httpClient ,
119- BaseURL : baseURL ,
120- Token : credentials .AccessToken ,
121- UserAgent : userAgent ,
122- RateLimiter : rate .NewLimiter (rate .Every (1 * time .Second ), 5 ),
120+ client : httpClient ,
121+ BaseURL : baseURL ,
122+ Token : credentials .AccessToken ,
123+ UserAgent : userAgent ,
124+ ReadRateLimiter : rate .NewLimiter (rate .Every (1 * time .Second ), 1 ),
125+ UpdateRateLimiter : rate .NewLimiter (rate .Every (4 * time .Second ), 1 ),
123126 }
124127 c .common .client = c
125128 c .HostConnectors = (* HostConnectorsService )(& c .common )
@@ -158,7 +161,13 @@ func (c *Client) setCommonHeaders(req *http.Request) {
158161// DoRequest executes an HTTP request with authentication and rate limiting.
159162// It automatically adds the Bearer token, sets headers, and handles errors.
160163func (c * Client ) DoRequest (req * http.Request ) ([]byte , error ) {
161- err := c .RateLimiter .Wait (context .Background ())
164+ var rateLimiter * rate.Limiter
165+ if req .Method == "GET" {
166+ rateLimiter = c .ReadRateLimiter
167+ } else {
168+ rateLimiter = c .UpdateRateLimiter
169+ }
170+ err := rateLimiter .Wait (context .Background ())
162171 if err != nil {
163172 return nil , err
164173 }
@@ -185,9 +194,42 @@ func (c *Client) DoRequest(req *http.Request) ([]byte, error) {
185194 return nil , & ErrClientResponse {status : res .StatusCode , body : string (body )}
186195 }
187196
197+ err = c .AssignLimits (res , rateLimiter )
198+ if err != nil {
199+ return nil , err
200+ }
201+
188202 return body , nil
189203}
190204
205+ // AssignLimits adjusts the rate limiter according to values received in response headers from the API
206+ func (c * Client ) AssignLimits (res * http.Response , rateLimiter * rate.Limiter ) error {
207+ rateHeader := res .Header .Get ("X-RateLimit-Replenish-Rate" )
208+ timeHeader := res .Header .Get ("X-RateLimit-Replenish-Time" )
209+ remainingHeader := res .Header .Get ("X-RateLimit-Remaining" )
210+
211+ if rateHeader != "" && timeHeader != "" && remainingHeader != "" {
212+ rateValue , err := strconv .Atoi (rateHeader )
213+ if err != nil {
214+ return err
215+ }
216+ timeValue , err := strconv .Atoi (timeHeader )
217+ if err != nil {
218+ return err
219+ }
220+ remainingValue , err := strconv .Atoi (remainingHeader )
221+ if err != nil {
222+ return err
223+ }
224+ if remainingValue <= 0 {
225+ remainingValue = 1
226+ }
227+ rateLimiter .SetLimit (rate .Every (time .Duration (timeValue * 1_000_000_000 / rateValue )))
228+ rateLimiter .SetBurst (remainingValue )
229+ }
230+ return nil
231+ }
232+
191233// GetV1Url returns the base URL for CloudConnexa API v1 endpoints.
192234func (c * Client ) GetV1Url () string {
193235 return c .BaseURL + "/api/v1"
0 commit comments