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.
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.
Activity *ActivityService
@ -323,7 +324,7 @@ func parseRate(r *http.Response) Rate {
// current rate.
func (c *Client) Rate() Rate {
c.rateMu.Lock()
rate := c.rate
rate := c.rateLimits[c.mostRecent]
c.rateMu.Unlock()
return rate
}
@ -334,6 +335,8 @@ func (c *Client) Rate() Rate {
// interface, the raw response body will be written to v, without attempting to
// first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
rateLimitCategory := category(req.URL.Path)
resp, err := c.client.Do(req)
if err != nil {
return nil, err
@ -348,7 +351,8 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
response := newResponse(resp)
c.rateMu.Lock()
c.rate = response.Rate
c.rateLimits[rateLimitCategory] = response.Rate
c.mostRecent = rateLimitCategory
c.rateMu.Unlock()
err = CheckResponse(resp)
@ -528,6 +532,8 @@ type RateLimits struct {
// The rate limit for non-search API requests. Unauthenticated
// requests are limited to 60 per hour. Authenticated requests are
// limited to 5,000 per hour.
//
// GitHub API docs: https://developer.github.com/v3/#rate-limiting
Core *Rate `json:"core"`
// The rate limit for search API requests. Unauthenticated requests
@ -542,6 +548,25 @@ func (r RateLimits) String() string {
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.
func (c *Client) RateLimit() (*Rate, *Response, error) {
limits, resp, err := c.RateLimits()
@ -567,6 +592,17 @@ func (c *Client) RateLimits() (*RateLimits, *Response, error) {
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
}


+ 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) {
c := NewClient(nil)


Loading…
Cancel
Save