Method: Discordrb::API.request
- Defined in:
- lib/discordrb/api.rb
.request(key, major_parameter, type, *attributes) ⇒ Object
Make an API request, including rate limit handling.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/discordrb/api.rb', line 93 def request(key, major_parameter, type, *attributes) # Add a custom user agent attributes.last[:user_agent] = user_agent if attributes.last.is_a? Hash # The most recent Discord rate limit requirements require the support of major parameters, where a particular route # and major parameter combination (*not* the HTTP method) uniquely identifies a RL bucket. key = [key, major_parameter].freeze begin mutex = @mutexes[key] ||= Mutex.new # Lock and unlock, i.e. wait for the mutex to unlock and don't do anything with it afterwards mutex_wait(mutex) # If the global mutex happens to be locked right now, wait for that as well. mutex_wait(@global_mutex) if @global_mutex.locked? response = nil begin response = raw_request(type, attributes) rescue RestClient::Exception => e response = e.response raise e rescue Discordrb::Errors::NoPermission => e if e.respond_to?(:_rc_response) response = e._rc_response else Discordrb::LOGGER.warn("NoPermission doesn't respond_to? _rc_response!") end raise e ensure if response handle_preemptive_rl(response.headers, mutex, key) if response.headers[:x_ratelimit_remaining] == '0' && !mutex.locked? else Discordrb::LOGGER.ratelimit('Response was nil before trying to preemptively rate limit!') end end rescue RestClient::TooManyRequests => e # If the 429 is from the global RL, then we have to use the global mutex instead. mutex = @global_mutex if e.response.headers[:x_ratelimit_global] == 'true' unless mutex.locked? response = JSON.parse(e.response) wait_seconds = response['retry_after'].to_i / 1000.0 Discordrb::LOGGER.ratelimit("Locking RL mutex (key: #{key}) for #{wait_seconds} seconds due to Discord rate limiting") trace("429 #{key.join(' ')}") # Wait the required time synchronized by the mutex (so other incoming requests have to wait) but only do it if # the mutex isn't locked already so it will only ever wait once sync_wait(wait_seconds, mutex) end retry end response end |