class RedisRateLimit::Period

Public Class Methods

new(name, options = {}) click to toggle source

Create an instance of Period. @param [String] name A unique namespace that identify the subject to track : users, emails, ip … @param [Hash] options Options hash @option options [String] :format ('%Y-%m-%dT%H:%M') Formated date that represents the time span to track @option options [Integer] :interval (60) The duration in seconds before the next reset @option options [Integer] :limit (60) How many transactions to perform during the defined interval @option options [Redis] :redis (nil) Redis client @return [Period] Period instance

# File lib/redis_rate_limit/period.rb, line 12
def initialize(name, options = {})
  @ratelimit_name = "rate_limit:#{name}"
  @format = options[:format] || '%Y-%m-%dT%H:%M'
  @interval = options[:interval] || 60
  @limit = options[:limit] || @interval
  @redis = options[:redis]
end

Public Instance Methods

clear(client) click to toggle source

Clean access history @param [String] client The value of the subject to track : 1234, foo@bar.com, 127.0.0.1 @return [Integer] access count

# File lib/redis_rate_limit/period.rb, line 78
def clear(client)
  @redis.expire(key(client), 0)
end
counter(client) click to toggle source

Get the access count for a given client within the current time range @param [String] client The value of the subject to track : 1234, foo@bar.com, 127.0.0.1 @return [Integer] access count

# File lib/redis_rate_limit/period.rb, line 63
def counter(client)
  range = Time.now.strftime(@format)
  @redis.hget(key(client), range).to_i
end
get_access(client) click to toggle source

Get an access if the rate limit is not exeeded @param [String] client The value of the subject to track : 1234, foo@bar.com, 127.0.0.1 @return [Hash] Access ticket

# File lib/redis_rate_limit/period.rb, line 23
def get_access(client)
  current_time = Time.now
  range = current_time.strftime(@format)
  reset = current_time.to_i + @interval - (current_time.to_i % @interval)
  key_client = key(client)
  counter = @redis.hincrby(key_client, range, 1)

  if counter < @limit
    pass = true
    remaining = @limit - counter
  else
    pass = false
    remaining = 0
  end

  return {
    "pass" => pass,
    "RateLimit" => {
      "X-RateLimit-Limit" => @limit,
      "X-RateLimit-Remaining" => remaining,
      "X-RateLimit-Counter" => counter,
      "X-RateLimit-Reset" => reset}
  }
end
get_access_or_wait(client) click to toggle source

Get an access if the rate limit is not exeeded or wait few seconds @param [String] client The value of the subject to track : 1234, foo@bar.com, 127.0.0.1 @return [Hash] Access ticket

# File lib/redis_rate_limit/period.rb, line 51
def get_access_or_wait(client)
  result = nil
  result = get_access(client)
  return result if result["pass"]
  time_to_sleep = result["RateLimit"]["X-RateLimit-Reset"] - Time.now.to_i
  sleep(time_to_sleep)
  get_access(client)
end
history(client) click to toggle source

Get access history for a given client @param [String] client The value of the subject to track : 1234, foo@bar.com, 127.0.0.1 @return [Array] Array of hash. key : time range, value : access counter

# File lib/redis_rate_limit/period.rb, line 71
def history(client)
  @redis.hgetall(key(client))
end

Private Instance Methods

key(client) click to toggle source
# File lib/redis_rate_limit/period.rb, line 84
def key(client)
  "#{@ratelimit_name}:#{client}"
end