Class: BridgeAPI::Client
- Inherits:
-
Footrest::Client
- Object
- Footrest::Client
- BridgeAPI::Client
show all
- Defined in:
- lib/bridge_api/client.rb,
lib/bridge_api/client/role.rb,
lib/bridge_api/client/user.rb,
lib/bridge_api/client/group.rb,
lib/bridge_api/client/account.rb,
lib/bridge_api/client/manager.rb,
lib/bridge_api/client/program.rb,
lib/bridge_api/client/data_dump.rb,
lib/bridge_api/client/enrollment.rb,
lib/bridge_api/client/affiliation.rb,
lib/bridge_api/client/live_course.rb,
lib/bridge_api/client/sub_account.rb,
lib/bridge_api/client/clone_object.rb,
lib/bridge_api/client/custom_field.rb,
lib/bridge_api/client/learner_item.rb,
lib/bridge_api/client/course_template.rb,
lib/bridge_api/client/program_enrollment.rb,
lib/bridge_api/client/live_course_session.rb,
lib/bridge_api/client/live_course_enrollment.rb
Defined Under Namespace
Modules: Account, Affiliation, CloneObject, CourseTemplate, CustomField, DataDump, Enrollment, Group, LearnerItem, LiveCourse, LiveCourseEnrollment, LiveCourseSession, Manager, Program, ProgramEnrollment, Role, SubAccount, User
Constant Summary
collapse
- DATA_DUMP_DOWNLOAD_PATH =
'/data_dumps/download'
- DATA_DUMP_PATH =
'/data_dumps'
- COURSE_TEMPLATE_PATH =
'/course_templates'
- ENROLLMENT_PATH =
'/enrollments'
- LTI_TOOLS_PATH =
'/lti_tools'
- PROGRAM_PATH =
'/programs'
- PROGRAM_ENROLLMENT_PATH =
'/learners'
- USER_PATH =
'/users'
- GROUPS_PATH =
'/groups'
- MANAGER_PATH =
'/managers'
- ADMIN_PATH =
'/admin'
- AUTHOR_PATH =
'/author'
- LEARNER_PATH =
'/learner'
- LEARNERS_PATH =
'/learners'
- LEARNER_ITEMS_PATH =
'/learner_items'
- CUSTOM_FIELD_PATH =
'/custom_fields'
- SUB_ACCOUNT_PATH =
'/sub_accounts'
- SUPPORT_PATH =
'/support'
- ACCOUNT_PATH =
'/accounts'
- CLONE_OBJECTS_PATH =
'/clone_objects'
- API_VERSION =
1
- API_PATH =
'/api'
- ROLE_PATH =
'/roles'
- AFFILIATED_SUBACCOUNTS =
'/affiliated_sub_accounts'
- BATCH_PATH =
'/batch'
- LIVE_COURSES_PATH =
'/live_courses'
- SESSIONS_PATH =
'/sessions'
- PUBLISH_PATH =
'/publish'
- WEB_CONFERENCE_PATH =
'/web_conference'
- RESTORE_PATH =
'/restore'
- DUE_DATE_PATH =
'/due_date'
- RESET_PATH =
'/reset'
- NEW_TEMPORARY_USERS =
'/new_temporary_users'
- LEARNER_ENROLLMENTS =
'/learner_enrollments'
- RESULT_MAPPING =
{}
Instance Method Summary
collapse
Constructor Details
#initialize(options = {}, &block) ⇒ Client
Returns a new instance of Client.
58
59
60
61
62
63
|
# File 'lib/bridge_api/client.rb', line 58
def initialize(options = {}, &block)
if BridgeAPI.enforce_rate_limits && has_token_pool?(options)
options = initialize_from_token_pool(options)
end
super
end
|
Instance Method Details
#apply_rate_limits(response) ⇒ Object
143
144
145
146
147
148
149
|
# File 'lib/bridge_api/client.rb', line 143
def apply_rate_limits(response)
limit = response.['x-rate-limit-remaining']
return if limit.nil?
BridgeAPI.logger.debug("BRIDGE RATE LIMIT REMAINING: #{limit} for key #{config[:api_key]}")
self.limit_remaining = limit.to_i
end
|
#convert_tokens(config) ⇒ Object
78
79
80
81
82
83
84
85
86
87
88
|
# File 'lib/bridge_api/client.rb', line 78
def convert_tokens(config)
return config unless config.has_key?(:api_tokens)
return config unless config[:api_tokens].is_a?(Array)
config[:api_keys] ||= {}
config[:api_tokens].each do |token|
decoded_token_array = Base64.strict_decode64(token).split(':')
config[:api_keys][decoded_token_array[0]] = decoded_token_array[1]
end
config.delete(:api_tokens)
config
end
|
#enforce_rate_limits ⇒ Object
#get_next_key(keys, current_key) ⇒ Object
111
112
113
114
115
116
117
118
119
|
# File 'lib/bridge_api/client.rb', line 111
def get_next_key(keys, current_key)
keys.delete(current_key)
usable_key = keys.find do |key|
limit = rate_limit(key)
current_key_limit = limit.present? ? limit.fetch('current') : 0
BridgeAPI.beginning_rate_limit - current_key_limit > BridgeAPI.rate_limit_threshold
end
usable_key || keys[rand(keys.length)]
end
|
#has_token_pool?(config) ⇒ Boolean
73
74
75
76
|
# File 'lib/bridge_api/client.rb', line 73
def has_token_pool?(config)
config[:api_keys].is_a?(Hash) && config[:api_keys].keys.count >= 1 ||
config[:api_tokens].is_a?(Array) && config[:api_tokens].count >= 1
end
|
#initialize_from_token_pool(config) ⇒ Object
90
91
92
93
94
95
96
|
# File 'lib/bridge_api/client.rb', line 90
def initialize_from_token_pool(config)
config = convert_tokens(config)
creds = config[:api_keys].first
config[:api_key] ||= creds[0]
config[:api_secret] ||= creds[1]
config
end
|
#limit_remaining ⇒ Object
151
152
153
154
155
156
157
158
159
160
161
162
|
# File 'lib/bridge_api/client.rb', line 151
def limit_remaining
if using_master_rate_limit?
limit = rate_limit(config[:api_key])
if limit.nil?
set_rate_limit(config[:api_key], 0)
limit = { current: 0 }.with_indifferent_access
end
limit['current']
else
BridgeAPI.rate_limits[config[:api_key]]
end
end
|
#limit_remaining=(value) ⇒ Object
164
165
166
167
168
169
170
171
|
# File 'lib/bridge_api/client.rb', line 164
def limit_remaining=(value)
if using_master_rate_limit?
set_rate_limit(config[:api_key], value)
else
BridgeAPI.rate_limits[config[:api_key]] = value
end
refresh_stale_tokens
end
|
#rate_limit(key) ⇒ Object
179
180
181
182
183
|
# File 'lib/bridge_api/client.rb', line 179
def rate_limit(key)
BridgeAPI.master_mutex.synchronize do
PaulWalker::RateLimit.get(key, key)
end
end
|
#rate_limit_reached? ⇒ Boolean
#refresh_stale_tokens ⇒ Object
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
# File 'lib/bridge_api/client.rb', line 185
def refresh_stale_tokens
return unless using_master_rate_limit?
return unless config[:api_keys].present?
api_keys = config[:api_keys].keys
api_keys.delete(config[:api_key])
api_keys.each do |key|
limit = rate_limit(key)
next unless limit.present?
if limit['timestamp'].present? && DateTime.parse(limit['timestamp']) < 1.minute.ago
BridgeAPI.logger.debug("Refreshing: #{key}")
set_rate_limit(key, 0)
end
end
end
|
#request(method, &block) ⇒ Object
Override Footrest request for ApiArray support
66
67
68
69
70
71
|
# File 'lib/bridge_api/client.rb', line 66
def request(method, &block)
enforce_rate_limits if rate_limit_reached?
response = connection.send(method, &block)
apply_rate_limits(response)
ApiArray.process_response(response, self, RESULT_MAPPING)
end
|
#rotate_token! ⇒ Object
rotates to the next token in the pool (by order in which they were provided)
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/bridge_api/client.rb', line 99
def rotate_token!
return unless config[:api_keys].present?
old_api_key = config[:api_key]
keys = config[:api_keys].keys
return if keys.count <= 1
key = get_next_key(keys, config[:api_key])
config[:api_key] = key
config[:api_secret] = config[:api_keys][key]
set_connection(config)
BridgeAPI.logger.debug("ROTATED TO KEY: #{config[:api_key]}")
end
|
#set_connection(config) ⇒ Object
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'lib/bridge_api/client.rb', line 200
def set_connection(config)
config[:logger] = config[:logging] if config[:logging]
@connection = Faraday.new(url: config[:prefix]) do |faraday|
faraday.request :multipart
faraday.request :url_encoded
if config[:logger] == true
faraday.response :logger
elsif config[:logger]
faraday.use Faraday::Response::Logger, config[:logger]
end
faraday.use Footrest::FollowRedirects, limit: 5 unless config[:follow_redirects] == false
faraday.adapter Faraday.default_adapter
faraday.use Footrest::ParseJson, content_type: /\bjson$/
faraday.use Footrest::RaiseFootrestErrors
faraday.use Footrest::Pagination
faraday.[:accept] = 'application/json'
faraday.[:user_agent] = 'Footrest'
if config[:api_key] && config[:api_secret]
faraday.[:authorization] = 'Basic ' + Base64.strict_encode64("#{config[:api_key]}:#{config[:api_secret]}")
elsif config[:token]
faraday.[:authorization] = "Bearer #{config[:token]}"
else
raise 'No api authorization provided'
end
end
end
|
#set_rate_limit(key, limit) ⇒ Object
#using_master_rate_limit? ⇒ Boolean
139
140
141
|
# File 'lib/bridge_api/client.rb', line 139
def using_master_rate_limit?
config[:master_rate_limit].present? || BridgeAPI.master_rate_limit.present?
end
|