Browse Source

Keep track of all rate limits in client.

In GitHub API, there are currently two categories of rate limits: core
and search. Previously, the client only tracked the rate limit from the
most recent API call. This change makes it track both rate limit
categories.

This will be useful in the following commit.
Dmitri Shuralyov 10 years ago
parent
commit
bbe5f62e3f
2 changed files with 47 additions and 4 deletions
  1. +40
    -4
      github/github.go
  2. +7
    -0
      github/github_test.go

+ 40
- 4
github/github.go View File

@ -86,8 +86,9 @@ type Client struct {
// User agent used when communicating with the GitHub API. // User agent used when communicating with the GitHub API.
UserAgent string UserAgent string
rateMu sync.Mutex
rate Rate // Rate limit for the client as determined by the most recent API call.
rateMu sync.Mutex
rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls.
mostRecent rateLimitCategory
// Services used for talking to different parts of the GitHub API. // Services used for talking to different parts of the GitHub API.
Activity *ActivityService Activity *ActivityService
@ -323,7 +324,7 @@ func parseRate(r *http.Response) Rate {
// current rate. // current rate.
func (c *Client) Rate() Rate { func (c *Client) Rate() Rate {
c.rateMu.Lock() c.rateMu.Lock()
rate := c.rate
rate := c.rateLimits[c.mostRecent]
c.rateMu.Unlock() c.rateMu.Unlock()
return rate return rate
} }
@ -334,6 +335,8 @@ func (c *Client) Rate() Rate {
// interface, the raw response body will be written to v, without attempting to // interface, the raw response body will be written to v, without attempting to
// first decode it. // first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
rateLimitCategory := category(req.URL.Path)
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
@ -348,7 +351,8 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
response := newResponse(resp) response := newResponse(resp)
c.rateMu.Lock() c.rateMu.Lock()
c.rate = response.Rate
c.rateLimits[rateLimitCategory] = response.Rate
c.mostRecent = rateLimitCategory
c.rateMu.Unlock() c.rateMu.Unlock()
err = CheckResponse(resp) err = CheckResponse(resp)
@ -528,6 +532,8 @@ type RateLimits struct {
// The rate limit for non-search API requests. Unauthenticated // The rate limit for non-search API requests. Unauthenticated
// requests are limited to 60 per hour. Authenticated requests are // requests are limited to 60 per hour. Authenticated requests are
// limited to 5,000 per hour. // limited to 5,000 per hour.
//
// GitHub API docs: https://developer.github.com/v3/#rate-limiting
Core *Rate `json:"core"` Core *Rate `json:"core"`
// The rate limit for search API requests. Unauthenticated requests // The rate limit for search API requests. Unauthenticated requests
@ -542,6 +548,25 @@ func (r RateLimits) String() string {
return Stringify(r) return Stringify(r)
} }
type rateLimitCategory uint8
const (
coreCategory rateLimitCategory = iota
searchCategory
categories // An array of this length will be able to contain all rate limit categories.
)
// category returns the rate limit category of the endpoint, determined by Request.URL.Path.
func category(path string) rateLimitCategory {
switch {
default:
return coreCategory
case strings.HasPrefix(path, "/search/"):
return searchCategory
}
}
// Deprecated: RateLimit is deprecated, use RateLimits instead. // Deprecated: RateLimit is deprecated, use RateLimits instead.
func (c *Client) RateLimit() (*Rate, *Response, error) { func (c *Client) RateLimit() (*Rate, *Response, error) {
limits, resp, err := c.RateLimits() limits, resp, err := c.RateLimits()
@ -567,6 +592,17 @@ func (c *Client) RateLimits() (*RateLimits, *Response, error) {
return nil, nil, err return nil, nil, err
} }
if response.Resources != nil {
c.rateMu.Lock()
if response.Resources.Core != nil {
c.rateLimits[coreCategory] = *response.Resources.Core
}
if response.Resources.Search != nil {
c.rateLimits[searchCategory] = *response.Resources.Search
}
c.rateMu.Unlock()
}
return response.Resources, resp, err return response.Resources, resp, err
} }


+ 7
- 0
github/github_test.go View File

@ -163,6 +163,13 @@ func TestNewClient(t *testing.T) {
} }
} }
// Ensure that length of Client.rateLimits is the same as number of fields in RateLimits struct.
func TestClient_rateLimits(t *testing.T) {
if got, want := len(Client{}.rateLimits), reflect.TypeOf(RateLimits{}).NumField(); got != want {
t.Errorf("len(Client{}.rateLimits) is %v, want %v", got, want)
}
}
func TestNewRequest(t *testing.T) { func TestNewRequest(t *testing.T) {
c := NewClient(nil) c := NewClient(nil)


Loading…
Cancel
Save