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