require 'active_support/core_ext/hash' require 'footrest/client' require 'paul_walker' module Bearcat class Client < Footrest::Client require 'bearcat/api_array' require 'bearcat/client/file_helper' require 'bearcat/client/assignments' require 'bearcat/client/blueprint_courses' require 'bearcat/client/courses' require 'bearcat/client/enrollments' require 'bearcat/client/outcome_groups' require 'bearcat/client/outcomes' require 'bearcat/client/sections' require 'bearcat/client/o_auth2' require 'bearcat/client/groups' require 'bearcat/client/group_categories' require 'bearcat/client/group_memberships' require 'bearcat/client/conferences' require 'bearcat/client/users' require 'bearcat/client/reports' require 'bearcat/client/accounts' require 'bearcat/client/submissions' require 'bearcat/client/conversations' require 'bearcat/client/modules' require 'bearcat/client/canvas_files' require 'bearcat/client/calendar_events' require 'bearcat/client/discussions' require 'bearcat/client/search' require 'bearcat/client/quizzes' require 'bearcat/client/assignment_groups' require 'bearcat/client/pages' require 'bearcat/client/files' require 'bearcat/client/folders' require 'bearcat/client/graph_ql' require 'bearcat/client/analytics' require 'bearcat/client/module_items' require 'bearcat/client/content_migrations' require 'bearcat/client/content_exports' require 'bearcat/client/custom_gradebook_columns' require 'bearcat/client/external_tools' require 'bearcat/client/rubric' require 'bearcat/client/rubric_assessment' require 'bearcat/client/rubric_association' include Assignments include Accounts include Analytics include BlueprintCourses include Courses include Enrollments include OutcomeGroups include Outcomes include Sections include OAuth2 include Groups include GroupCategories include GroupMemberships include Conferences include Users include Reports include Submissions include Conversations include Modules include CanvasFiles include CalendarEvents include Discussions include FileHelper include Search include Quizzes include AssignmentGroups include Pages include Files include Folders include GraphQL include ModuleItems include ContentMigrations include ContentExports include CustomGradebookColumns include ExternalTools include Rubric include RubricAssessment include RubricAssociation # Override Footrest request for ApiArray support def request(method, &block) enforce_rate_limits response = connection.send(method, &block) apply_rate_limits(response.headers['x-rate-limit-remaining']) ApiArray.process_response(response, self) end def enforce_rate_limits return unless limit_remaining.present? return unless limit_remaining < Bearcat.rate_limit_min tts = ((Bearcat.rate_limit_min - limit_remaining) / 5).ceil tts = Bearcat.min_sleep_seconds if tts < Bearcat.min_sleep_seconds tts = Bearcat.max_sleep_seconds if tts > Bearcat.max_sleep_seconds message = "Canvas API rate limit minimum #{Bearcat.rate_limit_min} reached. "\ "Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\ "Limit Remaining: #{limit_remaining}" Bearcat.logger.debug(message) sleep(tts) end def apply_rate_limits(limit) return if limit.nil? self.limit_remaining = limit.to_i end def using_master_rate_limit? config[:master_rate_limit].present? || Bearcat.master_rate_limit.present? end def limit_remaining if using_master_rate_limit? Bearcat.master_mutex.synchronize do limit = PaulWalker::RateLimit.get(config[:token], config[:token]) if limit.nil? PaulWalker::RateLimit.add(config[:token], config[:token], 0, Bearcat::rate_limit_min) limit = { current: 0 }.with_indifferent_access end Bearcat.logger.debug limit['current'].to_s limit['current'] end else Bearcat.rate_limits[config[:token]] end end def limit_remaining=(value) if using_master_rate_limit? Bearcat.master_mutex.synchronize do PaulWalker::RateLimit.add(config[:token], config[:token], value, Bearcat::rate_limit_min) end else Bearcat.rate_limits[config[:token]] = value end end end end