Refactor the ibb file receive as well

Stephen Paul Weber created

Change summary

.rubocop.yml    |   8 +
sgx-catapult.rb | 308 +++++++++++++++++++++-----------------------------
2 files changed, 134 insertions(+), 182 deletions(-)

Detailed changes

.rubocop.yml 🔗

@@ -35,7 +35,7 @@ Metrics/ModuleLength:
   Max: 1000
 
 Metrics/ParameterLists:
-  Max: 6
+  Max: 7
 
 Metrics/PerceivedComplexity:
   Max: 20
@@ -99,3 +99,9 @@ Style/MultilineBlockChain:
 
 Style/SpaceAroundEqualsInParameterDefault:
   EnforcedStyle: no_space
+
+Style/IndentArray:
+  EnforcedStyle: consistent
+
+Style/FirstParameterIndentation:
+  EnforcedStyle: consistent

sgx-catapult.rb 🔗

@@ -134,34 +134,22 @@ module SGXcatapult
 		write_to_stream rcpt
 	end
 
-	def self.to_catapult(m, num_dest, user_id, token, secret, users_num)
+	def self.call_catapult(token, secret, m, pth, body, head={}, code=[200])
 		EM::HttpRequest.new(
-			"https://api.catapult.inetwork.com/"\
-			"v1/users/#{user_id}/messages"
-		).post(
+			"https://api.catapult.inetwork.com/#{pth}"
+		).public_send(
+			m,
 			head: {
-				'Authorization' => [token, secret],
-				'Content-Type' => 'application/json'
-			},
-			body: JSON.dump(
-				from:             users_num,
-				to:               num_dest,
-				text:             m.body,
-				tag:
-					# callbacks need id and resourcepart
-					WEBrick::HTTPUtils.escape(m.id.to_s) +
-					' ' +
-					WEBrick::HTTPUtils.escape(
-						m.from.resource.to_s
-					),
-				receiptRequested: 'all',
-				callbackUrl:      ARGV[6]
-			)
+				'Authorization' => [token, secret]
+			}.merge(head),
+			body: body
 		).then { |http|
 			puts "API response to send: #{http.response} with code"\
 				" response.code #{http.response_header.status}"
 
-			if http.response_header.status != 201
+			if code.include?(http.response_header.status)
+				http.response
+			else
 				# TODO: add text; mention code number
 				EMPromise.reject(
 					[:cancel, 'internal-server-error']
@@ -170,8 +158,42 @@ module SGXcatapult
 		}
 	end
 
-	message :chat?, :body do |m|
-		EMPromise.resolve(m.to.node.to_s).then { |num_dest|
+	def self.to_catapult(s, murl, num_dest, user_id, token, secret, usern)
+		extra = if murl
+			{
+				media: murl
+			}
+		else
+			{
+				receiptRequested: 'all',
+				callbackUrl:      ARGV[6]
+			}
+		end
+
+		call_catapult(
+			token,
+			secret,
+			:post,
+			"v1/users/#{user_id}/messages",
+			JSON.dump(extra.merge(
+				from: usern,
+				to:   num_dest,
+				text: s.respond_to?(:body) ? s.body : '',
+				tag:
+					# callbacks need id and resourcepart
+					WEBrick::HTTPUtils.escape(s.id.to_s) +
+					' ' +
+					WEBrick::HTTPUtils.escape(
+						s.from.resource.to_s
+					)
+			)),
+			{'Content-Type' => 'application/json'},
+			[201]
+		)
+	end
+
+	def self.validate_num(num)
+		EMPromise.resolve(num.to_s).then { |num_dest|
 			if num_dest =~ /\A\+?[0-9]+(?:;.*)?\Z/
 				next num_dest if num_dest[0] == '+'
 				shortcode = extract_shortcode(num_dest)
@@ -179,29 +201,38 @@ module SGXcatapult
 			end
 			# TODO: text re num not (yet) supportd/implmentd
 			EMPromise.reject([:cancel, 'item-not-found'])
-		}.then { |num_dest|
-			cred_key = "catapult_cred-#{m.from.stripped}"
-			REDIS.lrange(cred_key, 0, 3).then { |creds|
-				[num_dest] + creds
-			}
-		}.then { |(num_dest, *creds)|
+		}
+	end
+
+	def self.fetch_catapult_cred_for(jid)
+		cred_key = "catapult_cred-#{jid.stripped}"
+		REDIS.lrange(cred_key, 0, 3).then { |creds|
 			if creds.length < 4
 				# TODO: add text re credentials not registered
 				EMPromise.reject(
 					[:auth, 'registration-required']
 				)
 			else
-				jid_key = "catapult_jid-#{num_dest}"
-				REDIS.get(jid_key).then { |jid|
-					[jid, num_dest] + creds
-				}
+				creds
 			end
+		}
+	end
+
+	message :chat?, :body do |m|
+		EMPromise.all([
+			validate_num(m.to.node),
+			fetch_catapult_cred_for(m.from)
+		]).then { |(num_dest, creds)|
+			jid_key = "catapult_jid-#{num_dest}"
+			REDIS.get(jid_key).then { |jid|
+				[jid, num_dest] + creds
+			}
 		}.then { |(jid, num_dest, *creds)|
 			# if destination user is in the system pass on directly
 			if jid
 				pass_on_message(m, creds.last, jid)
 			else
-				to_catapult(m, num_dest, *creds)
+				to_catapult(m, nil, num_dest, *creds)
 			end
 		}.catch { |e|
 			if e.is_a?(Array) && e.length == 2
@@ -432,158 +463,73 @@ module SGXcatapult
 	end
 
 	iq '/iq/ns:close', ns:	'http://jabber.org/protocol/ibb' do |i, cn|
-	begin
 		puts "IQc: #{i.inspect}"
 		write_to_stream i.reply
 
-		# TODO: refactor below so that "message :chat?" uses same code
-		num_dest = i.to.to_s.split('@', 2)[0]
-
-		if num_dest[0] != '+'
-			# check to see if a valid shortcode context is specified
-			num_and_context = num_dest.split(';', 2)
-			if num_and_context[1] and num_and_context[1] ==
-				'phone-context=ca-us.phone-context.soprani.ca'
-
-				# TODO: check if num_dest is fully numeric
-				num_dest = num_and_context[0]
-			else
-				# TODO: text re num not (yet) supportd/implmentd
-				write_to_stream error_msg(
-					i.reply, nil,
-					:cancel, 'item-not-found'
-				)
-				next
+		EMPromise.all([
+			validate_num(i.to.node),
+			fetch_catapult_cred_for(i.from)
+		]).then { |(num_dest, creds)|
+			# Gajim bug: <close/> has Jingle (not transport) sid; fix later
+			if not @jingle_fnames.key? cn[0]['sid']
+				puts 'ERROR: Not found in filename map: ' + cn[0]['sid']
+
+				next EMPromise.reject(:done)
+				# TODO: in case only Gajim's <data/> bug fixed, add map:
+				#cn[0]['sid'] = @jingle_tsids[cn[0]['sid']]
 			end
-		end
-
-		bare_jid = i.from.to_s.split('/', 2)[0]
-		cred_key = "catapult_cred-" + bare_jid
-
-		# TODO: connect at start of program instead
-		conn = Hiredis::Connection.new
-		conn.connect(ARGV[4], ARGV[5].to_i)
-
-		conn.write ["EXISTS", cred_key]
-		if conn.read == 0
-			conn.disconnect
-
-			# TODO: add text re credentials not being registered
-			write_to_stream error_msg(
-				i.reply, nil, :auth,
-				'registration-required'
-			)
-			next
-		end
-
-		conn.write ["LRANGE", cred_key, 0, 3]
-		user_id, api_token, api_secret, users_num = conn.read
-		conn.disconnect
-
-		# Gajim bug: <close/> has Jingle (not transport) sid; fix later
-		if not @jingle_fnames.key? cn[0]['sid']
-			puts 'ERROR: Not found in filename map: ' + cn[0]['sid']
-
-			next
-			# TODO: in case only Gajim's <data/> bug fixed, add map:
-			#cn[0]['sid'] = @jingle_tsids[cn[0]['sid']]
-		end
-
-		# upload cached data to server (before success reply)
-		media_name =
-			"#{Time.now.utc.iso8601}_#{SecureRandom.uuid}"\
-			"_#{@jingle_fnames[cn[0]['sid']]}"
-		puts 'name to save: ' + media_name
-
-		uri = URI.parse('https://api.catapult.inetwork.com')
-		http = Net::HTTP.new(uri.host, uri.port)
-		http.use_ssl = true
-		request = Net::HTTP::Put.new('/v1/users/' + user_id +
-			'/media/' + media_name)
-		request.basic_auth api_token, api_secret
-		request.body = @partial_data[cn[0]['sid']]
-		response = http.request(request)
-
-		puts 'eAPI response to send: ' + response.to_s + ' with code ' +
-			response.code + ', body "' + response.body + '"'
-
-		if response.code != '200'
-			# TODO: add text re unexpected code; mention code number
-			write_to_stream error_msg(
-				i.reply, nil, :cancel,
-				'internal-server-error'
-			)
-			next
-		end
 
-		uri = URI.parse('https://api.catapult.inetwork.com')
-		http = Net::HTTP.new(uri.host, uri.port)
-		http.use_ssl = true
-		request = Net::HTTP::Post.new('/v1/users/' + user_id +
-			'/messages')
-		request.basic_auth api_token, api_secret
-		request.add_field('Content-Type', 'application/json')
-		request.body = JSON.dump(
-			'from'			=> users_num,
-			'to'			=> num_dest,
-			'text'			=> '',
-			'media'			=> [
-				'https://api.catapult.inetwork.com/v1/users/' +
-				user_id + '/media/' + media_name
-			],
-			'tag'			=>
-				# callbacks need both the id and resourcepart
-				WEBrick::HTTPUtils.escape(i.id.to_s) + ' ' +
-				WEBrick::HTTPUtils.escape(
-					i.from.to_s.split('/', 2)[1].to_s
+			# upload cached data to server (before success reply)
+			media_name =
+				"#{Time.now.utc.iso8601}_#{SecureRandom.uuid}"\
+				"_#{@jingle_fnames[cn[0]['sid']]}"
+			puts 'name to save: ' + media_name
+
+			path = "/v1/users/#{creds.first}/media/#{media_name}"
+
+			EMPromise.all([
+				call_catapult(
+					*creds[1..2],
+					:put,
+					path,
+					@partial_data[cn[0]['sid']]
+				),
+				to_catapult(
+					i,
+					"https://api.catapult.inetwork.com/" +
+						path,
+					num_dest,
+					*creds
 				)
-			# TODO: add back when Bandwidth AP supports it (?); now:
-			#  "The ''messages'' resource property
-			#  ''receiptRequested'' is not supported for MMS"
-			#'receiptRequested'	=> 'all',
-			#'callbackUrl'		=> ARGV[6]
-		)
-		response = http.request(request)
-
-		puts 'mAPI response to send: ' + response.to_s + ' with code ' +
-			response.code + ', body "' + response.body + '"'
-
-		if response.code != '201'
-			# TODO: add text re unexpected code; mention code number
-			write_to_stream error_msg(
-				i.reply, nil, :cancel,
-				'internal-server-error'
-			)
-			next
-		end
-
-		@partial_data[cn[0]['sid']] = ''
-
-		# received the complete file so now close the stream
-		msg = Blather::Stanza::Iq.new :set
-		msg.to = i.from
-		msg.from = i.to
-
-		j = Nokogiri::XML::Node.new 'jingle', msg.document
-		j['xmlns'] = 'urn:xmpp:jingle:1'
-		j['action'] = 'session-terminate'
-		j['sid'] = @jingle_sids[cn[0]['sid']]
-		msg.add_child(j)
-
-		r = Nokogiri::XML::Node.new 'reason', msg.document
-		s = Nokogiri::XML::Node.new 'success', msg.document
-		r.add_child(s)
-		j.add_child(r)
-
-		puts 'RESPONSE1: ' + msg.inspect
-		write_to_stream msg
-
-	rescue Exception => e
-		puts 'Shutting down gateway due to exception 007: ' + e.message
-		SGXcatapult.shutdown
-		puts 'Gateway has terminated.'
-		EM.stop
-	end
+			])
+		}.then {
+			@partial_data[cn[0]['sid']] = ''
+
+			# received the complete file so now close the stream
+			msg = Blather::Stanza::Iq.new :set
+			msg.to = i.from
+			msg.from = i.to
+
+			j = Nokogiri::XML::Node.new 'jingle', msg.document
+			j['xmlns'] = 'urn:xmpp:jingle:1'
+			j['action'] = 'session-terminate'
+			j['sid'] = @jingle_sids[cn[0]['sid']]
+			msg.add_child(j)
+
+			r = Nokogiri::XML::Node.new 'reason', msg.document
+			s = Nokogiri::XML::Node.new 'success', msg.document
+			r.add_child(s)
+			j.add_child(r)
+
+			puts 'RESPONSE1: ' + msg.inspect
+			write_to_stream msg
+		}.catch { |e|
+			if e.is_a?(Array) && e.length == 2
+				write_to_stream error_msg(i.reply, nil, *e)
+			elsif e != :done
+				EMPromise.reject(e)
+			end
+		}.catch(&method(:panic))
 	end
 
 	iq '/iq/ns:query', ns:	'http://jabber.org/protocol/disco#items' do |i|