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'
- RESULT_MAPPING =
{}
Instance Method Summary
collapse
Constructor Details
#initialize(options = {}, &block) ⇒ Client
Returns a new instance of Client.
56
57
58
59
60
61
|
# File 'lib/bridge_api/client.rb', line 56
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
147
148
149
150
151
152
153
|
# File 'lib/bridge_api/client.rb', line 147
def apply_rate_limits(response)
limit = response.['x-rate-limit-remaining']
return if limit.nil?
BridgeAPI.logger.debug("BRIDGE RATE LIMIT REMAINING: #{limit}")
self.limit_remaining = limit.to_i
end
|
#enforce_rate_limits ⇒ Object
130
131
132
133
134
135
136
137
138
139
140
141
|
# File 'lib/bridge_api/client.rb', line 130
def enforce_rate_limits
return unless rate_limit_reached?
tts = ((BridgeAPI.beginning_rate_limit - limit_remaining) / 5).ceil
tts = BridgeAPI.min_sleep_seconds if tts < BridgeAPI.min_sleep_seconds
tts = BridgeAPI.max_sleep_seconds if tts > BridgeAPI.max_sleep_seconds
message = "Bridge API rate limit minimum #{BridgeAPI.rate_limit_threshold} reached for key: '#{config[:api_key]}'. "\
"Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\
"Limit Remaining: #{limit_remaining}"
BridgeAPI.logger.debug(message)
sleep(tts)
end
|
#get_next_key(keys, current_key) ⇒ Object
118
119
120
121
122
|
# File 'lib/bridge_api/client.rb', line 118
def get_next_key(keys, current_key)
i = keys.index(current_key) || -1
i = (i + 2) > keys.count ? 0 : (i + 1)
keys[i]
end
|
#has_token_pool?(config) ⇒ Boolean
78
79
80
81
|
# File 'lib/bridge_api/client.rb', line 78
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
Since a pool is passed in, initialize first token with the first token passed in
84
85
86
87
88
89
90
91
92
93
|
# File 'lib/bridge_api/client.rb', line 84
def initialize_from_token_pool(config)
if config[:api_keys].is_a?(Hash)
creds = config[:api_keys].first
config[:api_key] ||= creds[0]
config[:api_secret] ||= creds[1]
elsif config[:api_tokens].is_a?(Array)
config[:token] ||= config[:api_tokens].first
end
config
end
|
#limit_remaining ⇒ Object
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
# File 'lib/bridge_api/client.rb', line 155
def limit_remaining
if using_master_rate_limit?
BridgeAPI.master_mutex.synchronize do
limit = PaulWalker::RateLimit.get(config[:api_key], config[:api_key])
if limit.nil?
PaulWalker::RateLimit.add(config[:api_key], config[:api_key], 0, BridgeAPI.beginning_rate_limit)
limit = { current: 0 }.with_indifferent_access
end
limit['current']
end
else
BridgeAPI.rate_limits[config[:api_key]]
end
end
|
#limit_remaining=(value) ⇒ Object
170
171
172
173
174
175
176
177
178
|
# File 'lib/bridge_api/client.rb', line 170
def limit_remaining=(value)
if using_master_rate_limit?
BridgeAPI.master_mutex.synchronize do
PaulWalker::RateLimit.add(config[:api_key], config[:api_key], value, BridgeAPI.beginning_rate_limit)
end
else
BridgeAPI.rate_limits[config[:api_key]] = value
end
end
|
#rate_limit_reached? ⇒ Boolean
124
125
126
127
128
|
# File 'lib/bridge_api/client.rb', line 124
def rate_limit_reached?
return false unless BridgeAPI.enforce_rate_limits && limit_remaining.present?
limit_remaining < BridgeAPI.rate_limit_threshold
end
|
#request(method, &block) ⇒ Object
Override Footrest request for ApiArray support
64
65
66
67
68
69
70
71
72
73
74
75
76
|
# File 'lib/bridge_api/client.rb', line 64
def request(method, &block)
if has_token_pool?(config)
(config[:api_tokens] || config[:api_keys].keys).size.times do
break unless rate_limit_reached?
rotate_token!
end
end
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)
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
# File 'lib/bridge_api/client.rb', line 96
def rotate_token!
BridgeAPI.master_mutex.synchronize do
old_api_key = config[:api_key]
if config[:api_keys].is_a?(Hash)
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]
elsif config[:api_tokens].is_a?(Array)
keys = config[:api_tokens]
return if keys.count <= 1
token = get_next_key(keys, config[:token])
config[:token] = token
end
BridgeAPI.logger.debug('rotating API Keys')
set_connection(config)
end
end
|
#set_connection(config) ⇒ Object
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
# File 'lib/bridge_api/client.rb', line 180
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 ::FollowRedirects, limit: 5 unless config[:follow_redirects] == false
faraday.adapter Faraday.default_adapter
faraday.use ::ParseJson, content_type: /\bjson$/
faraday.use ::
faraday.use ::
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
|
#using_master_rate_limit? ⇒ Boolean
143
144
145
|
# File 'lib/bridge_api/client.rb', line 143
def using_master_rate_limit?
config[:master_rate_limit].present? || BridgeAPI.master_rate_limit.present?
end
|