1
1
module CodeshipApi
2
2
class Client
3
+ class RateLimitExceededError < StandardError ; end
4
+
3
5
def initialize ( username = USERNAME , password = PASSWORD )
4
6
@username = username
5
7
@password = password
@@ -10,21 +12,27 @@ def authenticated?
10
12
end
11
13
12
14
def get ( path )
13
- uri = URI . join ( ROOT , path . sub ( /^\/ / , "" ) )
15
+ rate_limit_protected! do
16
+ uri = URI . join ( ROOT , path . sub ( /^\/ / , "" ) )
14
17
15
- request = Net ::HTTP ::Get . new ( uri , default_headers )
16
- response = http . request ( request )
18
+ request = Net ::HTTP ::Get . new ( uri , default_headers )
19
+ response = http . request ( request )
17
20
18
- parsed_json_from ( response )
21
+ parse_errors_from ( response )
22
+ parsed_json_from ( response )
23
+ end
19
24
end
20
25
21
26
def post ( path )
22
- uri = URI . join ( ROOT , path . sub ( /^\/ / , "" ) )
27
+ rate_limit_protected! do
28
+ uri = URI . join ( ROOT , path . sub ( /^\/ / , "" ) )
23
29
24
- request = Net ::HTTP ::Post . new ( uri , default_headers )
25
- response = http . request ( request )
30
+ request = Net ::HTTP ::Post . new ( uri , default_headers )
31
+ response = http . request ( request )
26
32
27
- parsed_json_from ( response )
33
+ parse_errors_from ( response )
34
+ parsed_json_from ( response )
35
+ end
28
36
end
29
37
30
38
def organizations
@@ -39,6 +47,20 @@ def projects
39
47
40
48
attr_reader :username , :password
41
49
50
+ def rate_limit_protected! ( &block )
51
+ time_start = Time . now
52
+ block . call . tap do
53
+ duration = Time . now - time_start
54
+ sleep 1 . second - duration if duration < 1 . second
55
+ end
56
+ rescue RateLimitExceededError => e
57
+ sleep_duration = 60
58
+ print "waiting #{ sleep_duration } s for rate limit..."
59
+ sleep sleep_duration
60
+ puts " done."
61
+ rate_limit_protected! ( &block )
62
+ end
63
+
42
64
def token
43
65
authenticate unless authenticated?
44
66
authentication . access_token
@@ -49,18 +71,20 @@ def authentication
49
71
end
50
72
51
73
def authenticate
52
- uri = URI . join ( ROOT , 'auth' )
53
-
54
- request = Net ::HTTP ::Post . new ( uri . request_uri , {
55
- 'Content-Type' => 'application/json' ,
56
- 'Accept' => 'application/json'
57
- } ) . tap do |req |
58
- req . basic_auth ( username , password )
59
- end
74
+ rate_limit_protected! do
75
+ uri = URI . join ( ROOT , 'auth' )
76
+
77
+ request = Net ::HTTP ::Post . new ( uri . request_uri , {
78
+ 'Content-Type' => 'application/json' ,
79
+ 'Accept' => 'application/json'
80
+ } ) . tap do |req |
81
+ req . basic_auth ( username , password )
82
+ end
60
83
61
- response = http . request ( request )
84
+ response = http . request ( request )
62
85
63
- @authentication = Authentication . new ( JSON . parse ( response . body ) )
86
+ @authentication = Authentication . new ( JSON . parse ( response . body ) )
87
+ end
64
88
end
65
89
66
90
def http
@@ -79,12 +103,16 @@ def default_headers
79
103
}
80
104
end
81
105
82
- def parsed_json_from ( response )
83
- if response . body . length > 0
84
- JSON . parse ( response . body )
85
- else
86
- nil
106
+ def parse_errors_from ( response )
107
+ if response . code . to_i == 403 && response . entity == "Rate Limit Exceeded"
108
+ raise RateLimitExceededError . new ( response )
87
109
end
88
110
end
111
+
112
+ def parsed_json_from ( response )
113
+ return nil unless response . body . length > 0
114
+
115
+ JSON . parse ( response . body )
116
+ end
89
117
end
90
118
end
0 commit comments