1# frozen_string_literal: true
 2
 3require "value_semantics/monkey_patched"
 4
 5class ReachabilityRepo
 6	value_semantics do
 7		redis Anything(), default: LazyObject.new { REDIS }
 8		senders ArrayOf(String), default: CONFIG[:reachability_senders]
 9	end
10
11	EXPIRY = 60 * 60 # 1 hr
12
13	class SMS < self
14		def type
15			"sms"
16		end
17	end
18
19	class Voice < self
20		def type
21			"voice"
22		end
23	end
24
25	class NotTest
26		def filter(**)
27			EMPromise.resolve(yield)
28		end
29	end
30
31	class Test
32		def initialize(redis, key)
33			@redis = redis
34			@key = key
35		end
36
37		def filter(if_yes: ->(_) {}, **)
38			@redis.incr(@key).then(&if_yes)
39		end
40	end
41
42	# This one is for things that don't have a body.
43	# I still don't want to deliver them to the user, but I don't want to count
44	# them as a message either
45	class Ignore
46		def filter(if_yes: ->(_) {}, **)
47			EMPromise.resolve(if_yes.call(nil))
48		end
49	end
50
51	ACCEPTABLE_STANZA = Blather::Stanza::Message.new(nil, "I'm cool").freeze
52
53	# The customer is who is being contacted
54	# The initiator is the phone number trying to reach them
55	def find(customer, initiator, stanza: ACCEPTABLE_STANZA)
56		return EMPromise.resolve(NotTest.new) unless potential?(initiator)
57
58		testing?(customer).then do |active|
59			if active
60				stanza.body ? Test.new(redis, key(customer)) : Ignore.new
61			else
62				NotTest.new
63			end
64		end
65	end
66
67	# This creates the keys if they don't exist, and returns the value
68	def get_or_create(customer)
69		redis.set(key(customer), 0, "NX", "EX", EXPIRY).then {
70			redis.get(key(customer))
71		}
72	end
73
74protected
75
76	# This is basically an optimization to bail early without hitting a
77	# datastore for 99% of all messages
78	def potential?(tel)
79		senders.include?(tel)
80	end
81
82	# This checks if this particular customer has reachability turned on
83	def testing?(customer)
84		redis.exists(key(customer)).then { |v| v == 1 }
85	end
86
87	# This gets the particular key for this check
88	def key(customer)
89		"jmp_customer_reachability_#{type}-#{customer.customer_id}"
90	end
91end