<commit_before># frozen_string_literal: true

require 'rest-client'
require 'json'

require 'discordrb/errors'

# List of methods representing endpoints in Discord's API
module Discordrb::API
  # The base URL of the Discord REST API.
  APIBASE = 'https://discordapp.com/api'.freeze

  module_function

  # @return [String] the currently used API base URL.
  def api_base
    @api_base || APIBASE
  end

  # Sets the API base URL to something.
  def api_base=(value)
    @api_base = value
  end

  # @return [String] the bot name, previously specified using #bot_name=.
  def bot_name
    @bot_name
  end

  # Sets the bot name to something.
  def bot_name=(value)
    @bot_name = value
  end

  # Generate a user agent identifying this requester as discordrb.
  def user_agent
    # This particular string is required by the Discord devs.
    required = "DiscordBot (https://github.com/meew0/discordrb, v#{Discordrb::VERSION})"
    @bot_name ||= ''

    "rest-client/#{RestClient::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} discordrb/#{Discordrb::VERSION} #{required} #{@bot_name}"
  end

  # Resets all rate limit mutexes
  def reset_mutexes
    @mutexes = {
      message: Mutex.new
    }
  end

  # Performs a RestClient request.
  # @param type [Symbol] The type of HTTP request to use.
  # @param attributes [Array] The attributes for the request.
  def raw_request(type, attributes)
    RestClient.send(type, *attributes)
  rescue RestClient::Forbidden
    raise Discordrb::Errors::NoPermission, "The bot doesn't have the required permission to do this!"
  end

  # Make an API request. Utility function to implement message queueing
  # in the future
  def request(key, type, *attributes)
    if key
      # Lock and unlock, i. e. wait for the mutex to unlock and don't do anything with it afterwards
      @mutexes[key].lock
      @mutexes[key].unlock
    end

    # Add a custom user agent
    attributes.last[:user_agent] = user_agent if attributes.last.is_a? Hash

    begin
      response = raw_request(type, attributes)
    rescue RestClient::TooManyRequests
      wait_seconds = response[:retry_after].to_i / 1000.0
      LOGGER.debug("WARNING: Discord rate limiting will cause a delay of #{wait_seconds} seconds for the request: #{type} #{attributes}")
      sleep wait_seconds / 1000.0
      retry
    end

    response
  end

  # Make an avatar URL from the user and avatar IDs
  def avatar_url(user_id, avatar_id)
    "#{api_base}/users/#{user_id}/avatars/#{avatar_id}.jpg"
  end
<commit_msg>Put the wait logic into the begin block so it gets called again on a retry<commit_after># frozen_string_literal: true

require 'rest-client'
require 'json'

require 'discordrb/errors'

# List of methods representing endpoints in Discord's API
module Discordrb::API
  # The base URL of the Discord REST API.
  APIBASE = 'https://discordapp.com/api'.freeze

  module_function

  # @return [String] the currently used API base URL.
  def api_base
    @api_base || APIBASE
  end

  # Sets the API base URL to something.
  def api_base=(value)
    @api_base = value
  end

  # @return [String] the bot name, previously specified using #bot_name=.
  def bot_name
    @bot_name
  end

  # Sets the bot name to something.
  def bot_name=(value)
    @bot_name = value
  end

  # Generate a user agent identifying this requester as discordrb.
  def user_agent
    # This particular string is required by the Discord devs.
    required = "DiscordBot (https://github.com/meew0/discordrb, v#{Discordrb::VERSION})"
    @bot_name ||= ''

    "rest-client/#{RestClient::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} discordrb/#{Discordrb::VERSION} #{required} #{@bot_name}"
  end

  # Resets all rate limit mutexes
  def reset_mutexes
    @mutexes = {
      message: Mutex.new
    }
  end

  # Performs a RestClient request.
  # @param type [Symbol] The type of HTTP request to use.
  # @param attributes [Array] The attributes for the request.
  def raw_request(type, attributes)
    RestClient.send(type, *attributes)
  rescue RestClient::Forbidden
    raise Discordrb::Errors::NoPermission, "The bot doesn't have the required permission to do this!"
  end

  # Make an API request. Utility function to implement message queueing
  # in the future
  def request(key, type, *attributes)
    # Add a custom user agent
    attributes.last[:user_agent] = user_agent if attributes.last.is_a? Hash

    begin
      if key
        # Lock and unlock, i. e. wait for the mutex to unlock and don't do anything with it afterwards
        @mutexes[key].lock
        @mutexes[key].unlock
      end

      response = raw_request(type, attributes)
    rescue RestClient::TooManyRequests
      wait_seconds = response[:retry_after].to_i / 1000.0
      LOGGER.debug("WARNING: Discord rate limiting will cause a delay of #{wait_seconds} seconds for the request: #{type} #{attributes}")
      sleep wait_seconds / 1000.0
      retry
    end

    response
  end

  # Make an avatar URL from the user and avatar IDs
  def avatar_url(user_id, avatar_id)
    "#{api_base}/users/#{user_id}/avatars/#{avatar_id}.jpg"
  end

{'fraction_non_alphanumeric': 0.092523911770447, 'fraction_numerical': 0.004294358774155768, 'mean_word_length': 3.4556521739130437, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6233200', 'n_tokens_mistral': 1640, 'n_tokens_neox': 1585, 'n_words': 535}