Module: VelocityLimiter

Instance Method Summary collapse

Instance Method Details

#_velocity_limiter_params_validator!Object



21
22
23
24
25
26
27
# File 'lib/velocity_limiter.rb', line 21

def _velocity_limiter_params_validator!
	raise "Parent overloaded velocity_max_in_frame. Expected to be a ActiveSupport::Duration" unless velocity_max_in_frame.is_a? ActiveSupport::Duration
	raise "Parent overloaded velocity_frame. Expected to be a ActiveSupport::Duration" unless velocity_frame.is_a? ActiveSupport::Duration
	raise "Parent overloaded velocity_max. Expected to be a Integer" unless velocity_max.is_a? Integer
	raise "Parent overloaded velocity_max. Expected to be a Integer greater than 1" if velocity_max < 1
	raise "Parent overloaded cache_key. Expected to be a String" unless cache_key.is_a? String
end

#cache_delineatorObject



42
43
44
# File 'lib/velocity_limiter.rb', line 42

def cache_delineator
	','
end

#cache_keyObject



93
94
95
# File 'lib/velocity_limiter.rb', line 93

def cache_key
	raise "cache_key must be defined in the parent class"
end

#velocity_frameObject



35
36
# File 'lib/velocity_limiter.rb', line 35

def velocity_frame
end

#velocity_limit_message(metadata:) ⇒ Object



38
39
40
# File 'lib/velocity_limiter.rb', line 38

def velocity_limit_message(metadata:)
	"Velocity limit reached for SMS verification. You may try again in #{[:to_words]}"
end

#velocity_limit_reached?Boolean

Returns:

  • (Boolean)


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/velocity_limiter.rb', line 2

def velocity_limit_reached?
	_velocity_limiter_params_validator!

	 = 

	log(level: :info, msg: "#{cache_key} has attempted #{self.class.name} #{[:within_attempts_count]} times since #{[:threshold]}")

	if [:velocity_reached]
		log(level: :warn, msg: "#{cache_key} has been velocity limited. #{[:within_attempts_count]} attempts since #{[:threshold]}. MAX allowed is #{velocity_max}")
		log(level: :warn, msg: "#{cache_key} may try again in #{[:to_words]} :: #{[:attempt_again_at]}. Will fully reset at #{[:fully_reset_time]}")
		msg = velocity_limit_message(metadata: )
		return {reached: true, msg: msg}
	end

	vl_write!([:vl_write])

	{ reached: false }
end

#velocity_maxObject



32
33
# File 'lib/velocity_limiter.rb', line 32

def velocity_max
end

#velocity_max_in_frameObject



29
30
# File 'lib/velocity_limiter.rb', line 29

def velocity_max_in_frame
end

#vl_metadata(vl_arr: vl_read) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/velocity_limiter.rb', line 50

def (vl_arr: vl_read)
	threshold = vl_time - velocity_max_in_frame
	within_attempts = vl_arr.select do |time|
		time >= threshold
	end
	attempt_again_at = within_attempts.first ? (within_attempts.first + velocity_max_in_frame) : Time.zone.now

	obj = {}
	obj[:vl_write] = [within_attempts, vl_time].flatten
	obj[:fully_reset_time] = (within_attempts.last || Time.zone.now) + velocity_max_in_frame
	obj[:attempt_again_at] = attempt_again_at
	obj[:velocity_reached] = within_attempts.count >= velocity_max
	obj[:within_attempts_arr] = within_attempts
	obj[:within_attempts_count] = within_attempts.count
	obj[:attempts_remaining] = velocity_max - obj[:vl_write].count
	obj[:threshold] = threshold
	obj[:velocity_max] = velocity_max
	obj[:velocity_frame] = velocity_frame
	obj[:velocity_max_in_frame] = velocity_max_in_frame
	obj[:to_words] = distance_of_time_in_words(Time.zone.now, attempt_again_at, include_seconds: true)

	obj
end

#vl_readObject



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/velocity_limiter.rb', line 74

def vl_read
	json = Rails.cache.fetch(cache_key) || ''
	begin
		array = json.split(cache_delineator).map { |time| Time.zone.parse time }
	rescue StandardError => e
		log(level: :error, msg: "Failed to parse json strings into time. #{json}")
		array = []
	end
	log(level: :info, msg: "Read from #{cache_key} :: #{array}")

	array
end

#vl_timeObject



46
47
48
# File 'lib/velocity_limiter.rb', line 46

def vl_time
	@vl_time ||= Time.zone.now
end

#vl_write!(write) ⇒ Object



87
88
89
90
91
# File 'lib/velocity_limiter.rb', line 87

def vl_write!(write)
	cache_write = write.map(&:to_s).join(cache_delineator)
	log(level: :info, msg: "Writing [#{cache_write}] to #{cache_key}")
	Rails.cache.write(cache_key, cache_write, expires_in: velocity_frame)
end