bridge_api 0.1.66 → 0.1.67
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bridge_api/client.rb +72 -57
- data/lib/bridge_api/version.rb +1 -1
- data/lib/bridge_api.rb +1 -1
- data/spec/bridge_api/client/enrollment_spec.rb +0 -6
- data/spec/bridge_api/client_spec.rb +8 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29e3ffa7d065173483c89fd670fffd88f8b097a9aa90738bbcb89dee537f9b26
|
4
|
+
data.tar.gz: ba246bb521802607f2c7b54796fe3fe37b4e0b54f11f8d034c020d58a7b13604
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b7cd2e583404e406976e7a6fa264900125772525ab11caa3397d47466c052e825b5f91dc119edcc7fd98990a2b2603afa17c5f083ea57f0e9928855be32ca65
|
7
|
+
data.tar.gz: e63612d06e0049d375ffbcb63e7b912a1baea391565680b5bbcbb6e7aa2fbe43b5cdfe37080d545cb4e7a5ea62feea7b86a8f50d73306504b3de1ad6457dc88b
|
data/lib/bridge_api/client.rb
CHANGED
@@ -62,13 +62,6 @@ module BridgeAPI
|
|
62
62
|
|
63
63
|
# Override Footrest request for ApiArray support
|
64
64
|
def request(method, &block)
|
65
|
-
if has_token_pool?(config)
|
66
|
-
(config[:api_tokens] || config[:api_keys].keys).size.times do
|
67
|
-
break unless rate_limit_reached?
|
68
|
-
|
69
|
-
rotate_token!
|
70
|
-
end
|
71
|
-
end
|
72
65
|
enforce_rate_limits if rate_limit_reached?
|
73
66
|
response = connection.send(method, &block)
|
74
67
|
apply_rate_limits(response)
|
@@ -80,45 +73,46 @@ module BridgeAPI
|
|
80
73
|
config[:api_tokens].is_a?(Array) && config[:api_tokens].count >= 1
|
81
74
|
end
|
82
75
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
config[:token] ||= config[:api_tokens].first
|
76
|
+
def convert_tokens(config)
|
77
|
+
return config unless config.has_key?(:api_tokens)
|
78
|
+
return config unless config[:api_tokens].is_a?(Array)
|
79
|
+
config[:api_keys] ||= {}
|
80
|
+
config[:api_tokens].each do |token|
|
81
|
+
decoded_token_array = Base64.strict_decode64(token).split(':')
|
82
|
+
config[:api_keys][decoded_token_array[0]] = decoded_token_array[1]
|
91
83
|
end
|
84
|
+
config.delete(:api_tokens)
|
85
|
+
config
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize_from_token_pool(config)
|
89
|
+
config = convert_tokens(config)
|
90
|
+
creds = config[:api_keys].first
|
91
|
+
config[:api_key] ||= creds[0]
|
92
|
+
config[:api_secret] ||= creds[1]
|
92
93
|
config
|
93
94
|
end
|
94
95
|
|
95
96
|
# rotates to the next token in the pool (by order in which they were provided)
|
96
|
-
def rotate_token!
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
config[:api_secret] = config[:api_keys][key]
|
106
|
-
elsif config[:api_tokens].is_a?(Array)
|
107
|
-
keys = config[:api_tokens]
|
108
|
-
return if keys.count <= 1
|
109
|
-
|
110
|
-
token = get_next_key(keys, config[:token])
|
111
|
-
config[:token] = token
|
112
|
-
end
|
113
|
-
BridgeAPI.logger.debug('rotating API Keys')
|
114
|
-
set_connection(config)
|
115
|
-
end
|
97
|
+
def rotate_token!
|
98
|
+
old_api_key = config[:api_key]
|
99
|
+
keys = config[:api_keys].keys
|
100
|
+
return if keys.count <= 1
|
101
|
+
key = get_next_key(keys, config[:api_key])
|
102
|
+
config[:api_key] = key
|
103
|
+
config[:api_secret] = config[:api_keys][key]
|
104
|
+
set_connection(config)
|
105
|
+
BridgeAPI.logger.debug("ROTATED TO KEY: #{config[:api_key]}")
|
116
106
|
end
|
117
107
|
|
118
108
|
def get_next_key(keys, current_key)
|
119
|
-
|
120
|
-
|
121
|
-
|
109
|
+
keys.delete(current_key)
|
110
|
+
usable_key = keys.find do |key|
|
111
|
+
limit = rate_limit(key)
|
112
|
+
current_key_limit = limit.present? ? limit.fetch('current') : 0
|
113
|
+
BridgeAPI.beginning_rate_limit - current_key_limit > BridgeAPI.rate_limit_threshold
|
114
|
+
end
|
115
|
+
usable_key || keys[rand(keys.length)]
|
122
116
|
end
|
123
117
|
|
124
118
|
def rate_limit_reached?
|
@@ -130,14 +124,13 @@ module BridgeAPI
|
|
130
124
|
def enforce_rate_limits
|
131
125
|
return unless rate_limit_reached?
|
132
126
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"
|
138
|
-
|
139
|
-
|
140
|
-
sleep(tts)
|
127
|
+
rotate_token!
|
128
|
+
if rate_limit_reached?
|
129
|
+
sleep_time = rand(BridgeAPI.max_sleep_seconds)
|
130
|
+
sleep_time = BridgeAPI.min_sleep_seconds if sleep_time < BridgeAPI.min_sleep_seconds
|
131
|
+
BridgeAPI.logger.debug("Rate limit reached sleeping for #{sleep_time}")
|
132
|
+
sleep(sleep_time)
|
133
|
+
end
|
141
134
|
end
|
142
135
|
|
143
136
|
def using_master_rate_limit?
|
@@ -148,20 +141,18 @@ module BridgeAPI
|
|
148
141
|
limit = response.headers['x-rate-limit-remaining']
|
149
142
|
return if limit.nil?
|
150
143
|
|
151
|
-
BridgeAPI.logger.debug("BRIDGE RATE LIMIT REMAINING: #{limit}")
|
144
|
+
BridgeAPI.logger.debug("BRIDGE RATE LIMIT REMAINING: #{limit} for key #{config[:api_key]}")
|
152
145
|
self.limit_remaining = limit.to_i
|
153
146
|
end
|
154
147
|
|
155
148
|
def limit_remaining
|
156
149
|
if using_master_rate_limit?
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
limit = { current: 0 }.with_indifferent_access
|
162
|
-
end
|
163
|
-
limit['current']
|
150
|
+
limit = rate_limit(config[:api_key])
|
151
|
+
if limit.nil?
|
152
|
+
set_rate_limit(config[:api_key], 0)
|
153
|
+
limit = { current: 0 }.with_indifferent_access
|
164
154
|
end
|
155
|
+
limit['current']
|
165
156
|
else
|
166
157
|
BridgeAPI.rate_limits[config[:api_key]]
|
167
158
|
end
|
@@ -169,12 +160,36 @@ module BridgeAPI
|
|
169
160
|
|
170
161
|
def limit_remaining=(value)
|
171
162
|
if using_master_rate_limit?
|
172
|
-
|
173
|
-
PaulWalker::RateLimit.add(config[:api_key], config[:api_key], value, BridgeAPI.beginning_rate_limit)
|
174
|
-
end
|
163
|
+
set_rate_limit(config[:api_key], value)
|
175
164
|
else
|
176
165
|
BridgeAPI.rate_limits[config[:api_key]] = value
|
177
166
|
end
|
167
|
+
refresh_stale_tokens
|
168
|
+
end
|
169
|
+
|
170
|
+
def set_rate_limit(key, limit)
|
171
|
+
BridgeAPI.master_mutex.synchronize do
|
172
|
+
PaulWalker::RateLimit.add(key, key, limit, BridgeAPI.beginning_rate_limit)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def rate_limit(key)
|
177
|
+
BridgeAPI.master_mutex.synchronize do
|
178
|
+
PaulWalker::RateLimit.get(key, key)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def refresh_stale_tokens
|
183
|
+
return unless using_master_rate_limit?
|
184
|
+
api_keys = config[:api_keys].keys
|
185
|
+
api_keys.delete(config[:api_key])
|
186
|
+
api_keys.each do |key|
|
187
|
+
limit = rate_limit(key)
|
188
|
+
if limit['timestamp'].present? && DateTime.parse(limit['timestamp']) < 1.minute.ago
|
189
|
+
BridgeAPI.logger.debug("Refreshing: #{key}")
|
190
|
+
set_rate_limit(key, 0)
|
191
|
+
end
|
192
|
+
end
|
178
193
|
end
|
179
194
|
|
180
195
|
def set_connection(config)
|
data/lib/bridge_api/version.rb
CHANGED
data/lib/bridge_api.rb
CHANGED
@@ -27,12 +27,6 @@ describe BridgeAPI::Client::Enrollment do
|
|
27
27
|
expect(enrollments.length).to(eq(2))
|
28
28
|
end
|
29
29
|
|
30
|
-
it 'should update due date for enrollments' do
|
31
|
-
enrollment = [{ end_at: nil }]
|
32
|
-
response = @client.update_enrollment_due_date(1, enrollment)
|
33
|
-
expect(response.status).to(eq(200))
|
34
|
-
end
|
35
|
-
|
36
30
|
it 'should reset an enrollment for a course template' do
|
37
31
|
response = @client.reset_enrollment(1)
|
38
32
|
expect(response.status).to(eq(204))
|
@@ -52,7 +52,7 @@ describe BridgeAPI::Client do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should return true for tokens' do
|
55
|
-
config = { prefix: 'https://www.fake.com', api_tokens: %w[
|
55
|
+
config = { prefix: 'https://www.fake.com', api_tokens: %w[dGVzdDE6dGVzdDE= dGVzdDI6dGVzdDI=] }
|
56
56
|
client = BridgeAPI::Client.new(config)
|
57
57
|
expect(client.has_token_pool?(config)).to be_truthy
|
58
58
|
end
|
@@ -74,10 +74,10 @@ describe BridgeAPI::Client do
|
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'should take first from tokens' do
|
77
|
-
config = { prefix: 'https://www.fake.com', api_tokens: %w[
|
77
|
+
config = { prefix: 'https://www.fake.com', api_tokens: %w[dGVzdDE6dGVzdDE= dGVzdDI6dGVzdDI=] }
|
78
78
|
client = BridgeAPI::Client.new(config)
|
79
79
|
new_config = client.initialize_from_token_pool(config)
|
80
|
-
expect(new_config[:
|
80
|
+
expect(new_config[:api_key]).to eq('test1')
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -111,15 +111,16 @@ describe BridgeAPI::Client do
|
|
111
111
|
|
112
112
|
context 'with token pool' do
|
113
113
|
it 'should rotate to the next key' do
|
114
|
-
keys = %w[
|
114
|
+
keys = %w[dGVzdDE6dGVzdDE= dGVzdDI6dGVzdDI=]
|
115
115
|
config = { prefix: 'https://www.fake.com', api_tokens: keys }
|
116
116
|
client = BridgeAPI::Client.new(config)
|
117
|
-
expect(client.config[:
|
117
|
+
expect(client.config[:api_key]).to eq('test1')
|
118
118
|
client.rotate_token!
|
119
|
-
expect(client.config[:
|
119
|
+
expect(client.config[:api_key]).to eq('test2')
|
120
120
|
client.rotate_token!
|
121
|
-
expect(client.config[:
|
121
|
+
expect(client.config[:api_key]).to eq('test1')
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
126
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bridge_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.67
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jay Shaffer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|