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 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