Refactor knowledge of registration persistance to RegistrationRepo

Stephen Paul Weber created

Keeps all knowledge about redis key structure, etc, in one place.

Change summary

Gemfile                  |  1 
lib/registration_repo.rb | 54 ++++++++++++++++++++++++++++++++
sgx-bwmsgsv2.rb          | 69 +++++++++++------------------------------
3 files changed, 74 insertions(+), 50 deletions(-)

Detailed changes

Gemfile 🔗

@@ -9,6 +9,7 @@ gem 'em-http-request'
 gem 'em_promise.rb'
 gem 'eventmachine'
 gem 'goliath'
+gem 'lazy_object'
 gem 'log4r'
 gem 'rack', '< 2'
 gem 'redis'

lib/registration_repo.rb 🔗

@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'lazy_object'
+
+class RegistrationRepo
+	class Conflict < StandardError; end
+
+	def initialize(redis: LazyObject.new { REDIS })
+		@redis = redis
+	end
+
+	def find(jid)
+		REDIS.lrange(cred_key(jid), 0, 3)
+	end
+
+	def find_jid(tel)
+		REDIS.get(jid_key(tel))
+	end
+
+	def put(jid, *creds)
+		tel = creds.last
+
+		EMPromise.all([
+			find(jid),
+			REDIS.set(
+				jid_key(tel),
+				Blather::JID.new(jid).stripped.to_s,
+				"NX", "GET"
+			)
+		]).then { |(oldcreds, oldjid)|
+			if oldjid && oldjid != jid.stripped.to_s
+				raise Conflict, "Another user exists for #{tel}"
+			end
+
+			if !oldcreds.empty? && oldcreds != creds
+				REDIS.set(jid_key(tel), oldjid).then do
+					raise Conflict, "Another user exists for #{jid}"
+				end
+			end
+		}.then {
+			REDIS.rpush(cred_key(jid), *creds)
+		}
+	end
+
+protected
+
+	def cred_key(jid)
+		"catapult_cred-#{Blather::JID.new(jid).stripped}"
+	end
+
+	def jid_key(tel)
+		"catapult_jid-#{tel}"
+	end
+end

sgx-bwmsgsv2.rb 🔗

@@ -34,6 +34,8 @@ require 'log4r'
 
 require 'em_promise'
 
+require_relative 'lib/registration_repo'
+
 def panic(e)
 	puts "Shutting down gateway due to exception: #{e.message}"
 	puts e.backtrace
@@ -84,6 +86,7 @@ end
 module SGXbwmsgsv2
 	extend Blather::DSL
 
+	@registration_repo = RegistrationRepo.new
 	@client = SGXClient.new
 	@gateway_features = [
 		"http://jabber.org/protocol/disco#info",
@@ -385,8 +388,7 @@ module SGXbwmsgsv2
 	end
 
 	def self.fetch_catapult_cred_for(jid)
-		cred_key = "catapult_cred-#{jid.stripped}"
-		REDIS.lrange(cred_key, 0, 3).then { |creds|
+		@registration_repo.find(jid).then { |creds|
 			if creds.length < 4
 				# TODO: add text re credentials not registered
 				EMPromise.reject(
@@ -408,15 +410,13 @@ module SGXbwmsgsv2
 			validate_num(m),
 			fetch_catapult_cred_for(m.from)
 		]).then { |(num_dest, creds)|
-			jid_key = "catapult_jid-#{num_dest}"
-			REDIS.get(jid_key).then { |jid|
+			@registration_repo.find_jid(num_dest).then { |jid|
 				[jid, num_dest] + creds
 			}
 		}.then { |(jid, num_dest, *creds)|
 			if jid
-				cred_key = "catapult_cred-#{jid}"
-				REDIS.lrange(cred_key, 0, 0).then { |other_user|
-					[jid, num_dest] + creds + other_user
+				@registration_repo.find(jid).then { |other_user|
+					[jid, num_dest] + creds + other_user.first
 				}
 			else
 				[jid, num_dest] + creds + [nil]
@@ -542,44 +542,13 @@ module SGXbwmsgsv2
 	end
 
 	def self.check_then_register(i, *creds)
-		jid_key = "catapult_jid-#{creds.last}"
-		bare_jid = i.from.stripped
-		cred_key = "catapult_cred-#{bare_jid}"
-
-		REDIS.get(jid_key).then { |existing_jid|
-			if existing_jid && existing_jid != bare_jid
-				# TODO: add/log text: credentials exist already
-				EMPromise.reject([:cancel, 'conflict'])
-			end
-		}.then {
-			REDIS.lrange(cred_key, 0, 3)
-		}.then { |existing_creds|
-			# TODO: add/log text: credentials exist already
-			if existing_creds.length == 4 && creds != existing_creds
-				EMPromise.reject([:cancel, 'conflict'])
-			elsif existing_creds.length < 4
-				REDIS.rpush(cred_key, *creds).then { |length|
-					if length != 4
-						EMPromise.reject([
-							:cancel,
-							'internal-server-error'
-						])
-					end
-				}
-			end
-		}.then {
-			# not necessary if existing_jid non-nil, easier this way
-			REDIS.set(jid_key, bare_jid)
-		}.then { |result|
-			if result != 'OK'
-				# TODO: add txt re push failure
-				EMPromise.reject(
-					[:cancel, 'internal-server-error']
-				)
-			end
-		}.then {
-			write_to_stream i.reply
-		}
+		registration_repo
+			.put(i.from, *creds)
+			.catch_only(RegistrationRepo::Conflict) { |e|
+				EMPromise.reject([:cancel, 'conflict', e.message])
+			}.then {
+				write_to_stream i.reply
+			}
 	end
 
 	def self.creds_from_registration_query(qn)
@@ -756,9 +725,8 @@ module SGXbwmsgsv2
 			process_registration(i, qn)
 		when :get
 			bare_jid = i.from.stripped
-			cred_key = "catapult_cred-#{bare_jid}"
-			REDIS.lindex(cred_key, 3).then { |existing_number|
-				reply = registration_form(i.reply, existing_number)
+			@registration_repo.find(bare_jid).then { |creds|
+				reply = registration_form(i.reply, creds.last)
 				puts "RESPONSE2: #{reply.inspect}"
 				write_to_stream reply
 			}
@@ -794,6 +762,8 @@ end
 class WebhookHandler < Goliath::API
 	use Goliath::Rack::Params
 
+	@registration_repo = RegistrationRepo.new
+
 	def response(env)
 		# TODO: add timestamp grab here, and MUST include ./tai version
 
@@ -858,8 +828,7 @@ class WebhookHandler < Goliath::API
 				';phone-context=ca-us.phone-context.soprani.ca'
 		end
 
-		jid_key = "catapult_jid-#{users_num}"
-		bare_jid = REDIS.get(jid_key).promise.sync
+		bare_jid = @registration_repo.find_jid(users_num).sync
 
 		if !bare_jid
 			puts "jid_key (#{jid_key}) DNE; BW API misconfigured?"