diff --git a/Gemfile b/Gemfile index ac412f48c2305c0cdf90472514e3ff6f21b1d7ec..1b7c6dc627574b52cf118348211ea52c66afb683 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,8 @@ gem "em-synchrony" gem "em_promise.rb", "~> 0.0.3" gem "eventmachine" gem "money-open-exchange-rates" +gem "multibases" +gem "multihashes" gem "ougai" gem "roda" gem "ruby-bandwidth-iris" diff --git a/config-schema.dhall b/config-schema.dhall index 154da2a853daf41b80177f4e85a1f39968e03cf2..e06e4d975d398a45f928981842db0394235f5896 100644 --- a/config-schema.dhall +++ b/config-schema.dhall @@ -1,6 +1,7 @@ { activation_amount : Natural , admins : List Text , adr : Text +, bandwidth_app : Text , bandwidth_peer : Text , bandwidth_site : Text , braintree : @@ -27,6 +28,8 @@ , interac : Text , notify_admin : Text , notify_from : Text +, ogm_path : Text +, ogm_web_root : Text , oxr_app_id : Text , payable : Text , plans : @@ -45,5 +48,6 @@ , upstream_domain : Text , web : < Inet : { interface : Text, port : Natural } | Unix : Text > , web_register : { from : Text, to : Text } +, web_root : Text , xep0157 : List { label : Text, value : Text, var : Text } } diff --git a/config.dhall.sample b/config.dhall.sample index 465e0d6751fda427a1b2540af784c37beb88dad9..f03acaa9c1e269a772d0d53ce2911f6a06f3e213 100644 --- a/config.dhall.sample +++ b/config.dhall.sample @@ -11,6 +11,9 @@ in }, sgx = "component2.localhost", web = ListenOn.Inet { interface = "::1", port = env:PORT ? 8080 }, + web_root = "https://example.com", + ogm_path = "/var/www/media.example.com", + ogm_web_root = "https://media.example.com", creds = { account = "00000", username = "dashboard user", @@ -30,6 +33,7 @@ in }, bandwidth_site = "", bandwidth_peer = "", + bandwidth_app = "", -- This can be any voice app braintree = { environment = "sandbox", merchant_id = "", diff --git a/lib/backend_sgx.rb b/lib/backend_sgx.rb index b4fec109b3ca575ba9365a88d6289f12ca99d66e..3cbbc5f72c89ac146b7938adc0ac0ed607d38d46 100644 --- a/lib/backend_sgx.rb +++ b/lib/backend_sgx.rb @@ -37,4 +37,8 @@ class BackendSgx def set_fwd_timeout(timeout) REDIS.set("catapult_fwd_timeout-#{from_jid}", timeout) end + + def set_ogm_url(url) + REDIS.set("catapult_ogm_url-#{from_jid}", url) + end end diff --git a/lib/customer.rb b/lib/customer.rb index f4dde9c402cfa0b9e1d4405c0cae685c27b266c7..537ed99f0670acb01cc985fea1dab7324a0a73b5 100644 --- a/lib/customer.rb +++ b/lib/customer.rb @@ -22,7 +22,7 @@ class Customer attr_reader :customer_id, :balance, :jid def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan, :currency, :merchant_account, :plan_name, :auto_top_up_amount - def_delegators :@sgx, :register!, :registered?, + def_delegators :@sgx, :register!, :registered?, :set_ogm_url, :set_fwd_timeout, :fwd, :transcription_enabled def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage diff --git a/lib/customer_fwd.rb b/lib/customer_fwd.rb index 3b309559a158e55329afa079be82b9894ac9d747..b43f79383749a09411068cf3ae20849fcde6e668 100644 --- a/lib/customer_fwd.rb +++ b/lib/customer_fwd.rb @@ -25,6 +25,15 @@ class CustomerFwd end end + def create_call_request + request = Bandwidth::ApiCreateCallRequest.new.tap do |cc| + cc.to = to + cc.call_timeout = timeout.to_i + end + yield request if block_given? + request + end + class Tel < CustomerFwd attr_reader :timeout diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 3a4f19f77450fa333f0163e6be39fba54ff5941a..22c122307f9ee726a982ee3458270c29637d850b 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -423,11 +423,7 @@ Command.new( # Commands that just pass through to the SGX { "number-display" => ["Display JMP Number"], - "configure-calls" => ["Configure Calls"], - "record-voicemail-greeting" => [ - "Record Voicemail Greeting", - list_for: ->(fwd: nil, **) { !!fwd } - ] + "configure-calls" => ["Configure Calls"] }.each do |node, args| Command.new(node, *args) { Command.customer.then do |customer| @@ -436,6 +432,26 @@ Command.new( }.register(self, guards: [node: node]).then(&CommandList.method(:register)) end +Command.new( + "ogm", + "Record Voicemail Greeting", + list_for: ->(fwd: nil, **) { !!fwd }, + customer_repo: CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new) +) { + Command.customer.then do |customer| + BANDWIDTH_VOICE.create_call( + CONFIG[:creds][:account], + body: customer.fwd.create_call_request do |cc| + cc.from = customer.registered?.phone + cc.application_id = CONFIG[:bandwidth_app] + cc.answer_url = "#{CONFIG[:web_root]}/ogm/start?" \ + "customer_id=#{customer.customer_id}" + end + ) + Command.finish("You will now receive a call.") + end +}.register(self).then(&CommandList.method(:register)) + Command.new( "credit cards", "Credit Card Settings and Management" diff --git a/views/record_ogm.slim b/views/record_ogm.slim new file mode 100644 index 0000000000000000000000000000000000000000..a957603d757ec4d5ac3a83ba7fdf3d2e89e73d77 --- /dev/null +++ b/views/record_ogm.slim @@ -0,0 +1,5 @@ +doctype xml +Response + SpeakSentence At the tone, say your new voicemail greeting. Then, hang up. + PlayAudio= "/beep.mp3" + Record recordingAvailableUrl="/ogm?customer_id=#{customer_id}" fileFormat="mp3" diff --git a/web.rb b/web.rb index a57efb8b459246c8a51a85adb266da6877cf9a9b..75145a1590e79f3d45803ef2fb946f7b75693d69 100644 --- a/web.rb +++ b/web.rb @@ -2,6 +2,8 @@ require "digest" require "forwardable" +require "multibases" +require "multihashes" require "roda" require "thin" require "sentry-ruby" @@ -11,6 +13,37 @@ require_relative "lib/roda_capture" require_relative "lib/roda_em_promise" require_relative "lib/rack_fiber" +class OGMDownload + def initialize(url) + @digest = Digest::SHA512.new + @f = Tempfile.open("ogm") + @req = EM::HttpRequest.new(url, tls: { verify_peer: true }) + end + + def download + http = @req.aget + http.stream do |chunk| + @digest << chunk + @f.write chunk + end + http.then { @f.close }.catch do |e| + @f.close! + EMPromise.reject(e) + end + end + + def cid + Multibases.encode( + "base58btc", + [1, 85].pack("C*") + Multihashes.encode(@digest.digest, "sha2-512") + ).pack.to_s + end + + def path + @f.path + end +end + # rubocop:disable Metrics/ClassLength class Web < Roda use Rack::Fiber # Must go first! @@ -225,17 +258,15 @@ class Web < Roda sgx_repo: Bwmsgsv2Repo.new ).find_by_tel(params["to"]).then(&:fwd).then do |fwd| if fwd - body = Bandwidth::ApiCreateCallRequest.new.tap do |cc| - cc.to = fwd.to - cc.from = params["from"] - cc.application_id = params["applicationId"] - cc.call_timeout = fwd.timeout.to_i - cc.answer_url = url inbound_calls_path(nil) - cc.disconnect_url = url inbound_calls_path(:transfer_complete) - end true_inbound_call[pseudo_call_id] = params["callId"] outbound_transfers[pseudo_call_id] = BANDWIDTH_VOICE.create_call( - CONFIG[:creds][:account], body: body + 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 render :pause, locals: { duration: 300 } else @@ -268,6 +299,26 @@ class Web < Roda end end + r.on "ogm" do + r.post "start" do + render :record_ogm, locals: { customer_id: params["customer_id"] } + end + + r.post do + jmp_media_url = params["mediaUrl"].sub( + /\Ahttps:\/\/voice.bandwidth.com\/api\/v2\/accounts\/\d+/, + "https://jmp.chat" + ) + ogm = OGMDownload.new(jmp_media_url) + ogm.download.then do + File.rename(ogm.path, "#{CONFIG[:ogm_path]}/#{ogm.cid}") + CustomerRepo.new.find(params["customer_id"]).then do |customer| + customer.set_ogm_url("#{CONFIG[:ogm_web_root]}/#{ogm.cid}.mp3") + end + end + end + end + r.public end end