# frozen_string_literal: true module RateLimitHeaders extend ActiveSupport::Concern class_methods do def override_rate_limit_headers(method_name, options = {}) around_action(only: method_name, if: :current_account) do |_controller, block| begin block.call ensure rate_limiter = RateLimiter.new(current_account, options) rate_limit_headers = rate_limiter.to_headers response.headers.merge!(rate_limit_headers) unless response.headers['X-RateLimit-Remaining'].present? && rate_limit_headers['X-RateLimit-Remaining'].to_i > response.headers['X-RateLimit-Remaining'].to_i end end end end included do before_action :set_rate_limit_headers, if: :rate_limited_request? end private def set_rate_limit_headers apply_header_limit apply_header_remaining apply_header_reset end def rate_limited_request? !request.env['rack.attack.throttle_data'].nil? end def apply_header_limit response.headers['X-RateLimit-Limit'] = rate_limit_limit end def rate_limit_limit api_throttle_data[:limit].to_s end def apply_header_remaining response.headers['X-RateLimit-Remaining'] = rate_limit_remaining end def rate_limit_remaining (api_throttle_data[:limit] - api_throttle_data[:count]).to_s end def apply_header_reset response.headers['X-RateLimit-Reset'] = rate_limit_reset end def rate_limit_reset (request_time + reset_period_offset).iso8601(6) end def api_throttle_data most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] - v[:count] } request.env['rack.attack.throttle_data'][most_limited_type] end def request_time @_request_time ||= Time.now.utc end def reset_period_offset api_throttle_data[:period] - request_time.to_i % api_throttle_data[:period] end end