class Discorb::HTTP

A class to handle http requests. @private

Public Class Methods

multipart(payload, files) click to toggle source

A helper method to send multipart/form-data requests.

@param [Hash] payload The payload to send. @param [Array<Discorb::File>] files The files to send.

@return [Array[String, String]] The boundary and body.

# File lib/discorb/http.rb, line 180
    def self.multipart(payload, files)
      boundary = "DiscorbBySevenC7CMultipartFormData#{Time.now.to_f}"
      str_payloads = [<<~HTTP]
        Content-Disposition: form-data; name="payload_json"
        Content-Type: application/json

        #{payload.to_json}
      HTTP
      files.each do |single_file|
        str_payloads << <<~HTTP
          Content-Disposition: form-data; name="file"; filename="#{single_file.filename}"
          Content-Type: #{single_file.content_type}

          #{single_file.io.read}
        HTTP
      end
      [boundary, "--#{boundary}\n#{str_payloads.join("\n--#{boundary}\n")}\n--#{boundary}--"]
    end
new(client) click to toggle source

@!visibility private

# File lib/discorb/http.rb, line 14
def initialize(client)
  @client = client
  @ratelimit_handler = RatelimitHandler.new(client)
end

Public Instance Methods

delete(path, headers: nil, audit_log_reason: nil, **kwargs) click to toggle source

Execute a DELETE request. @macro async

@param [String] path The path to the resource. @param [Hash] headers The headers to send with the request. @param [String] audit_log_reason The audit log reason to send with the request. @param [Hash] kwargs The keyword arguments.

@return [Array[Net::HTTPResponse, Hash]] The response and as JSON. @return [Array[Net::HTTPResponse, nil]] The response was 204.

@raise [Discorb::HTTPError] The request was failed.

# File lib/discorb/http.rb, line 153
def delete(path, headers: nil, audit_log_reason: nil, **kwargs)
  Async do |task|
    @ratelimit_handler.wait("DELETE", path)
    resp = http.delete(get_path(path), get_headers(headers, "", audit_log_reason))
    data = get_response_data(resp)
    @ratelimit_handler.save("DELETE", path, resp)
    test_error(if resp.code == "429"
      task.sleep(data[:retry_after])
      delete(path, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
    else
      [resp, data]
    end)
  end
end
get(path, headers: nil, audit_log_reason: nil, **kwargs) click to toggle source

Execute a GET request. @macro async

@param [String] path The path to the resource. @param [Hash] headers The headers to send with the request. @param [String] audit_log_reason The audit log reason to send with the request. @param [Hash] kwargs The keyword arguments.

@return [Array[Net::HTTPResponse, Hash]] The response and as JSON. @return [Array[Net::HTTPResponse, nil]] The response was 204.

@raise [Discorb::HTTPError] The request was failed.

# File lib/discorb/http.rb, line 33
def get(path, headers: nil, audit_log_reason: nil, **kwargs)
  Async do |task|
    @ratelimit_handler.wait("GET", path)
    resp = http.get(get_path(path), get_headers(headers, "", audit_log_reason), **kwargs)
    data = get_response_data(resp)
    @ratelimit_handler.save("GET", path, resp)
    test_error(if resp.code == "429"
      @client.log.warn "Ratelimit exceeded for #{path}, trying again in #{data[:retry_after]} seconds."
      task.sleep(data[:retry_after])
      get(path, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
    else
      [resp, data]
    end)
  end
end
inspect() click to toggle source
# File lib/discorb/http.rb, line 168
def inspect
  "#<#{self.class} client=#{@client}>"
end
patch(path, body = "", headers: nil, audit_log_reason: nil, **kwargs) click to toggle source

Execute a PATCH request. @macro async

@param [String] path The path to the resource. @param [String, Hash] body The body of the request. @param [Hash] headers The headers to send with the request. @param [String] audit_log_reason The audit log reason to send with the request. @param [Hash] kwargs The keyword arguments.

@return [Array[Net::HTTPResponse, Hash]] The response and as JSON. @return [Array[Net::HTTPResponse, nil]] The response was 204.

@raise [Discorb::HTTPError] The request was failed.

# File lib/discorb/http.rb, line 94
def patch(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
  Async do |task|
    @ratelimit_handler.wait("PATCH", path)
    resp = http.patch(get_path(path), get_body(body), get_headers(headers, body, audit_log_reason), **kwargs)
    data = get_response_data(resp)
    @ratelimit_handler.save("PATCH", path, resp)
    test_error(if resp.code == "429"
      task.sleep(data[:retry_after])
      patch(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
    else
      [resp, data]
    end)
  end
end
post(path, body = "", headers: nil, audit_log_reason: nil, **kwargs) click to toggle source

Execute a POST request. @macro async

@param [String] path The path to the resource. @param [String, Hash] body The body of the request. @param [Hash] headers The headers to send with the request. @param [String] audit_log_reason The audit log reason to send with the request. @param [Hash] kwargs The keyword arguments.

@return [Array[Net::HTTPResponse, Hash]] The response and as JSON. @return [Array[Net::HTTPResponse, nil]] The response was 204.

@raise [Discorb::HTTPError] The request was failed.

# File lib/discorb/http.rb, line 64
def post(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
  Async do |task|
    @ratelimit_handler.wait("POST", path)
    resp = http.post(get_path(path), get_body(body), get_headers(headers, body, audit_log_reason), **kwargs)
    data = get_response_data(resp)
    @ratelimit_handler.save("POST", path, resp)
    test_error(if resp.code == "429"
      task.sleep(data[:retry_after])
      post(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
    else
      [resp, data]
    end)
  end
end
put(path, body = "", headers: nil, audit_log_reason: nil, **kwargs) click to toggle source

Execute a PUT request. @macro async

@param [String] path The path to the resource. @param [String, Hash] body The body of the request. @param [Hash] headers The headers to send with the request. @param [String] audit_log_reason The audit log reason to send with the request. @param [Hash] kwargs The keyword arguments.

@return [Array[Net::HTTPResponse, Hash]] The response and as JSON. @return [Array[Net::HTTPResponse, nil]] The response was 204.

@raise [Discorb::HTTPError] The request was failed.

# File lib/discorb/http.rb, line 124
def put(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
  Async do |task|
    @ratelimit_handler.wait("PUT", path)
    resp = http.put(get_path(path), get_body(body), get_headers(headers, body, audit_log_reason), **kwargs)
    data = get_response_data(resp)
    @ratelimit_handler.save("PUT", path, resp)
    test_error(if resp.code == "429"
      task.sleep(data[:retry_after])
      put(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
    else
      [resp, data]
    end)
  end
end

Private Instance Methods

get_body(body) click to toggle source
# File lib/discorb/http.rb, line 227
def get_body(body)
  if body.nil?
    ""
  elsif body.is_a?(String)
    body
  else
    recr_utf8(body).to_json
  end
end
get_headers(headers, body = "", audit_log_reason = nil) click to toggle source
# File lib/discorb/http.rb, line 215
def get_headers(headers, body = "", audit_log_reason = nil)
  ret = if body.nil? || body == ""
      { "User-Agent" => USER_AGENT, "authorization" => "Bot #{@client.token}" }
    else
      { "User-Agent" => USER_AGENT, "authorization" => "Bot #{@client.token}",
        "content-type" => "application/json" }
    end
  ret.merge(headers) if !headers.nil? && headers.length.positive?
  ret["X-Audit-Log-Reason"] = audit_log_reason unless audit_log_reason.nil?
  ret
end
get_path(path) click to toggle source
# File lib/discorb/http.rb, line 237
def get_path(path)
  full_path = if path.start_with?("https://")
      path
    else
      API_BASE_URL + path
    end
  URI(full_path).path
end
get_response_data(resp) click to toggle source
# File lib/discorb/http.rb, line 246
def get_response_data(resp)
  if resp["Via"].nil?
    raise CloudFlareBanError.new(@client, resp)
  end
  rd = resp.body
  if rd.nil? || rd.empty?
    nil
  else
    JSON.parse(rd, symbolize_names: true)
  end
end
http() click to toggle source
# File lib/discorb/http.rb, line 258
def http
  https = Net::HTTP.new("discord.com", 443)
  https.use_ssl = true
  https
end
recr_utf8(data) click to toggle source
# File lib/discorb/http.rb, line 264
def recr_utf8(data)
  case data
  when Hash
    data.each do |k, v|
      data[k] = recr_utf8(v)
    end
    data
  when Array
    data.each_index do |i|
      data[i] = recr_utf8(data[i])
    end
    data
  when String
    data.dup.force_encoding(Encoding::UTF_8)
  else
    data
  end
end
test_error(ary) click to toggle source
# File lib/discorb/http.rb, line 201
def test_error(ary)
  resp, data = *ary
  case resp.code
  when "400"
    raise BadRequestError.new(resp, data)
  when "403"
    raise ForbiddenError.new(resp, data)
  when "404"
    raise NotFoundError.new(resp, data)
  else
    [resp, data]
  end
end