diff --git a/lib/bwmsgsv2_repo.rb b/lib/bwmsgsv2_repo.rb index 312563122ea83d88ffa8274c5f319ba22dfea488..2aa498e6a91dab4c7f922e9d6be77f36fdfe179a 100644 --- a/lib/bwmsgsv2_repo.rb +++ b/lib/bwmsgsv2_repo.rb @@ -20,7 +20,7 @@ class Bwmsgsv2Repo fetch_raw(sgx.from_jid).then do |(((ogm_url, fwd_time, fwd), trans_d), reg)| sgx.with({ ogm_url: ogm_url, - fwd: CustomerFwd.for(fwd, fwd_time), + fwd: CustomerFwd.for(uri: fwd, timeout: fwd_time), transcription_enabled: !trans_d, registered?: reg }.compact) diff --git a/lib/customer_fwd.rb b/lib/customer_fwd.rb index b43f79383749a09411068cf3ae20849fcde6e668..a1a2e8dc3f7c92b3a60a851f0fcb43c9f2117e15 100644 --- a/lib/customer_fwd.rb +++ b/lib/customer_fwd.rb @@ -1,17 +1,25 @@ # frozen_string_literal: true +require "value_semantics/monkey_patched" require "uri" class CustomerFwd - def self.for(uri, timeout) + def self.for(uri:, timeout:) timeout = Timeout.new(timeout) - return if !uri || timeout.zero? + return None.new(uri: uri, timeout: timeout) if !uri || timeout.zero? + if uri =~ /\Asip:(.*)@sip.cheogram.com\Z/ + uri = "xmpp:#{$1.gsub(/%([0-9A-F]{2})/i) { $1.to_i(16).chr }}" + end URIS.fetch(uri.split(":", 2).first.to_sym) { raise "Unknown forward URI: #{uri}" - }.new(uri, timeout) + }.new(uri: uri, timeout: timeout) end class Timeout + def self.new(s) + s.is_a?(self) ? s : super + end + def initialize(s) @timeout = s.nil? || s.to_i.negative? ? 300 : s.to_i end @@ -25,54 +33,51 @@ class CustomerFwd end end - def create_call_request + value_semantics do + uri Either(String, NilClass) + # rubocop:disable Style/RedundantSelf + self.timeout Timeout, coerce: Timeout.method(:new) + # rubocop:enable Style/RedundantSelf + end + + def with(new_attrs) + CustomerFwd.for(to_h.merge(new_attrs)) + end + + def create_call(account) request = Bandwidth::ApiCreateCallRequest.new.tap do |cc| cc.to = to cc.call_timeout = timeout.to_i + yield cc if block_given? end - yield request if block_given? - request + BANDWIDTH_VOICE.create_call(account, body: request).data.call_id end class Tel < CustomerFwd - attr_reader :timeout - - def initialize(uri, timeout) - @tel = uri.sub(/^tel:/, "") - @timeout = timeout - end - def to - @tel + uri.sub(/^tel:/, "") end end class SIP < CustomerFwd - attr_reader :timeout - - def initialize(uri, timeout) - @uri = uri - @timeout = timeout - end - def to - @uri + uri end end class XMPP < CustomerFwd - attr_reader :timeout - - def initialize(uri, timeout) - @jid = uri.sub(/^xmpp:/, "") - @timeout = timeout - end - def to - "sip:#{ERB::Util.url_encode(@jid)}@sip.cheogram.com" + jid = uri.sub(/^xmpp:/, "") + "sip:#{ERB::Util.url_encode(jid)}@sip.cheogram.com" end end + class None < CustomerFwd + def create_call; end + + def to; end + end + URIS = { tel: Tel, sip: SIP, diff --git a/test/test_customer_fwd.rb b/test/test_customer_fwd.rb new file mode 100644 index 0000000000000000000000000000000000000000..de530302a86caf52e29656dec5852cda31f9e6d1 --- /dev/null +++ b/test/test_customer_fwd.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require "test_helper" +require "customer_fwd" + +class Rantly + def jid + v = Blather::JID.new(Blather::JID.new(string, string).stripped.to_s) + guard !v.to_s.to_s.empty? + v + end +end + +class CustomerFwdTest < Minitest::Test + property(:for_xmpp) { jid } + def for_xmpp(jid) + sip = "sip:#{ERB::Util.url_encode(jid.to_s)}@sip.cheogram.com" + fwd = CustomerFwd.for(uri: "xmpp:#{jid}", timeout: 10) + assert_kind_of CustomerFwd::XMPP, fwd + assert_equal sip, fwd.to + end + + property(:for_xmpp_sip) { jid } + def for_xmpp_sip(jid) + sip = "sip:#{ERB::Util.url_encode(jid.to_s)}@sip.cheogram.com" + fwd = CustomerFwd.for(uri: sip, timeout: 10) + assert_kind_of CustomerFwd::XMPP, fwd + assert_equal sip, fwd.to + end + + property(:for_tel) { "+#{string(:digit)}" } + def for_tel(tel) + fwd = CustomerFwd.for(uri: "tel:#{tel}", timeout: 10) + assert_kind_of CustomerFwd::Tel, fwd + assert_equal tel, fwd.to + end + + property(:for_sip) { "#{string(:alnum)}@#{string(:alnum)}.example.com" } + def for_sip(sip) + fwd = CustomerFwd.for(uri: "sip:#{sip}", timeout: 10) + assert_kind_of CustomerFwd::SIP, fwd + assert_equal "sip:#{sip}", fwd.to + end + + property(:for_bogus) { string } + def for_bogus(bogus) + assert_raises(RuntimeError) do + CustomerFwd.for(uri: "bogus:#{bogus}", timeout: 10) + end + end +end diff --git a/web.rb b/web.rb index 75145a1590e79f3d45803ef2fb946f7b75693d69..530c6ec9eaf994387b4ef267b4d20037582d1673 100644 --- a/web.rb +++ b/web.rb @@ -257,17 +257,16 @@ class Web < Roda CustomerRepo.new( sgx_repo: Bwmsgsv2Repo.new ).find_by_tel(params["to"]).then(&:fwd).then do |fwd| - if fwd + call = fwd.create_call(CONFIG[:creds][:account]) do |cc| true_inbound_call[pseudo_call_id] = params["callId"] - outbound_transfers[pseudo_call_id] = BANDWIDTH_VOICE.create_call( - CONFIG[:creds][:account], - body: fwd.create_call_request do |cc| - cc.from = params["from"] - cc.application_id = params["applicationId"] - cc.answer_url = url inbound_calls_path(nil) - cc.disconnect_url = url inbound_calls_path(:transfer_complete) - end - ).data.call_id + cc.from = params["from"] + cc.application_id = params["applicationId"] + cc.answer_url = url inbound_calls_path(nil) + cc.disconnect_url = url inbound_calls_path(:transfer_complete) + end + + if call + outbound_transfers[pseudo_call_id] = call render :pause, locals: { duration: 300 } else render :redirect, locals: { to: inbound_calls_path(:voicemail) }