class Sinatra::RateLimiter::RateLimit

Attributes

options[RW]
request[RW]
settings[RW]

Public Class Methods

new(bucket, limits) click to toggle source
# File lib/sinatra/rate-limiter.rb, line 102
def initialize(bucket, limits)
  @bucket      = bucket
  @limits      = limits
  @time_prefix = get_min_time_prefix(@limits)
end

Public Instance Methods

headers() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 121
def headers
  headers = []

  header_prefix = @options.header_prefix + (@bucket.eql?('default') ? '' : '-' + @bucket)
  limit_no = 0 if @limits.length > 1
  @limits.each do |limit|
    limit_no = limit_no + 1 if limit_no
    headers << [header_prefix + (limit_no ? "-#{limit_no}" : '') + '-Limit',     limit[:requests]]
    headers << [header_prefix + (limit_no ? "-#{limit_no}" : '') + '-Remaining', limit_remaining(limit)]
    headers << [header_prefix + (limit_no ? "-#{limit_no}" : '') + '-Reset',     limit_reset(limit)]
  end

  return headers
end
history(seconds=0) click to toggle source
# File lib/sinatra/rate-limiter.rb, line 117
def history(seconds=0)
  redis_history.select{|t| seconds.eql?(0) ? true : t > (Time.now.to_f - seconds)}
end
identifier() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 113
def identifier
  @identifier ||= @options.identifier.call(request)
end
limit_remaining(limit) click to toggle source
# File lib/sinatra/rate-limiter.rb, line 136
def limit_remaining(limit)
  limit[:requests] - history(limit[:seconds]).length
end
limit_reset(limit) click to toggle source
# File lib/sinatra/rate-limiter.rb, line 140
def limit_reset(limit)
  limit[:seconds] - (Time.now.to_f - history(limit[:seconds]).first.to_f).to_i
end
limits_exceeded?() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 144
def limits_exceeded?
  exceeded = @limits.select {|limit| limit_remaining(limit) < 1}.sort_by{|e| e[:seconds]}.last

  if exceeded
    try_again = limit_reset(exceeded)
    return exceeded.merge({try_again: try_again.to_i, bucket: @bucket})
  end
end
log_request() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 153
def log_request
  redis.setex(
    [namespace, identifier, @bucket, Time.now.to_f.to_s].join('/'),
    @settings.rate_limiter_redis_expires,
    nil)
end
options=(options) click to toggle source
# File lib/sinatra/rate-limiter.rb, line 108
def options=(options)
  options = settings.rate_limiter_default_options.merge(options)
  @options = Struct.new(*options.keys).new(*options.values)
end

Private Instance Methods

get_min_time_prefix(limits) click to toggle source
# File lib/sinatra/rate-limiter.rb, line 176
def get_min_time_prefix(limits)
  now    = Time.now.to_f
  oldest = Time.now.to_f - limits.sort_by{|l| -l[:seconds]}.first[:seconds]

  return now.to_s[0..((now/oldest).to_s.split(/^1\.|[1-9]+/)[1].length)].to_i.to_s
end
namespace() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 172
def namespace
  @settings.rate_limiter_redis_namespace
end
redis() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 168
def redis
  @settings.rate_limiter_redis_conn
end
redis_history() click to toggle source
# File lib/sinatra/rate-limiter.rb, line 162
def redis_history
  @history ||= redis.
    keys("#{[namespace,identifier,@bucket].join('/')}/#{@time_prefix}*").
    map{|k| k.split('/')[3].to_f}
end