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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9ca9ab902293aba483f19e3672a1c0c60aa19c2aca4175bf34a2a4db7bae6d8
4
- data.tar.gz: 004f3fee360e5c413572bf7f636ed75f8e765936668bf03a6fa7437e6b5b0441
3
+ metadata.gz: 29e3ffa7d065173483c89fd670fffd88f8b097a9aa90738bbcb89dee537f9b26
4
+ data.tar.gz: ba246bb521802607f2c7b54796fe3fe37b4e0b54f11f8d034c020d58a7b13604
5
5
  SHA512:
6
- metadata.gz: 9c5475c3391696f44fc7564fe112bfb07c850bdd9ba4c8d29164f4db30ebbdd7d17f02a096a4dbcbc4b5193c57716d66f733f2ab6e913544216389f13a8c1871
7
- data.tar.gz: 82a529c351861196e9a0cce6bcc0e581120af60cc709d75526ac8de6dd6c5f5c8b9ba20c9c4e15b00b646b8144a350f40fa5a1c91ec96b3d28644eb1dca3716a
6
+ metadata.gz: 0b7cd2e583404e406976e7a6fa264900125772525ab11caa3397d47466c052e825b5f91dc119edcc7fd98990a2b2603afa17c5f083ea57f0e9928855be32ca65
7
+ data.tar.gz: e63612d06e0049d375ffbcb63e7b912a1baea391565680b5bbcbb6e7aa2fbe43b5cdfe37080d545cb4e7a5ea62feea7b86a8f50d73306504b3de1ad6457dc88b
@@ -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
- # Since a pool is passed in, initialize first token with the first token passed in
84
- def initialize_from_token_pool(config)
85
- if config[:api_keys].is_a?(Hash)
86
- creds = config[:api_keys].first
87
- config[:api_key] ||= creds[0]
88
- config[:api_secret] ||= creds[1]
89
- elsif config[:api_tokens].is_a?(Array)
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
- BridgeAPI.master_mutex.synchronize do
98
- old_api_key = config[:api_key]
99
- if config[:api_keys].is_a?(Hash)
100
- keys = config[:api_keys].keys
101
- return if keys.count <= 1
102
-
103
- key = get_next_key(keys, config[:api_key])
104
- config[:api_key] = key
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
- i = keys.index(current_key) || -1
120
- i = (i + 2) > keys.count ? 0 : (i + 1)
121
- keys[i]
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
- tts = ((BridgeAPI.beginning_rate_limit - limit_remaining) / 5).ceil
134
- tts = BridgeAPI.min_sleep_seconds if tts < BridgeAPI.min_sleep_seconds
135
- tts = BridgeAPI.max_sleep_seconds if tts > BridgeAPI.max_sleep_seconds
136
- message = "Bridge API rate limit minimum #{BridgeAPI.rate_limit_threshold} reached for key: '#{config[:api_key]}'. "\
137
- "Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\
138
- "Limit Remaining: #{limit_remaining}"
139
- BridgeAPI.logger.debug(message)
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
- BridgeAPI.master_mutex.synchronize do
158
- limit = PaulWalker::RateLimit.get(config[:api_key], config[:api_key])
159
- if limit.nil?
160
- PaulWalker::RateLimit.add(config[:api_key], config[:api_key], 0, BridgeAPI.beginning_rate_limit)
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
- BridgeAPI.master_mutex.synchronize do
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BridgeAPI
4
- VERSION = '0.1.66' unless defined?(BridgeAPI::VERSION)
4
+ VERSION = '0.1.67' unless defined?(BridgeAPI::VERSION)
5
5
  end
data/lib/bridge_api.rb CHANGED
@@ -26,7 +26,7 @@ module BridgeAPI
26
26
  end
27
27
 
28
28
  def max_sleep_seconds
29
- @max_sleep_seconds ||= 60
29
+ @max_sleep_seconds ||= 30
30
30
  end
31
31
 
32
32
  def master_rate_limit
@@ -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[token1 token2] }
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[token1 token2] }
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[:token]).to eq('token1')
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[token1 token2]
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[:token]).to eq('token1')
117
+ expect(client.config[:api_key]).to eq('test1')
118
118
  client.rotate_token!
119
- expect(client.config[:token]).to eq('token2')
119
+ expect(client.config[:api_key]).to eq('test2')
120
120
  client.rotate_token!
121
- expect(client.config[:token]).to eq('token1')
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.66
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-01-10 00:00:00.000000000 Z
11
+ date: 2022-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler