bridge_api 0.1.66 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|