class Strait::Rule
Public Class Methods
new(name:, rule:, config:)
click to toggle source
# File lib/strait/rule.rb, line 5 def initialize(name:, rule:, config:) @name = name @rule = rule @config = config end
Public Instance Methods
call(user)
click to toggle source
# File lib/strait/rule.rb, line 11 def call(user) period_count_for(user) <= @rule[:count] end
to_h()
click to toggle source
# File lib/strait/rule.rb, line 15 def to_h @rule end
Private Instance Methods
bucket_for(time)
click to toggle source
# File lib/strait/rule.rb, line 46 def bucket_for(time) (time.to_f / bucket_length).floor * bucket_length end
bucket_length()
click to toggle source
# File lib/strait/rule.rb, line 50 def bucket_length @bucket_length ||= @rule[:period] / @rule[:buckets] end
key_for(user)
click to toggle source
# File lib/strait/rule.rb, line 54 def key_for(user) "strait:#{@name}-#{@rule[:count]}/#{@rule[:period]}:#{user}" end
period_count_for(user)
click to toggle source
Get the in-period hit count for a user
# File lib/strait/rule.rb, line 22 def period_count_for(user) key = key_for(user) # Round the timestamp to get the bucket bucket_time = bucket_for(Time.now) first_bucket = ((Time.now.to_i - @rule[:period]) / bucket_length).floor @config.redis_pool.with do |redis| redis.hincrby(key, bucket_time, 1) # We need to iterate the list once to total the counts, so we use that one iteration to also # find any buckets which should be removed. results = redis.hgetall(key).each_with_object(total: 0, delete: []) do |(time, count), out| if time.to_i < first_bucket out[:delete] << time else out[:total] += count.to_i end end redis.hdel(key, *results[:delete]) unless results[:delete].empty? results[:total] end end