M Gemfile => Gemfile +2 -0
@@ 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"
M config-schema.dhall => config-schema.dhall +4 -0
@@ 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 }
}
M config.dhall.sample => config.dhall.sample +4 -0
@@ 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 = "",
M lib/backend_sgx.rb => lib/backend_sgx.rb +4 -0
@@ 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
M lib/customer.rb => lib/customer.rb +1 -1
@@ 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
M lib/customer_fwd.rb => lib/customer_fwd.rb +9 -0
@@ 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
M sgx_jmp.rb => sgx_jmp.rb +21 -5
@@ 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|
@@ 437,6 433,26 @@ Command.new(
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"
) {
A views/record_ogm.slim => views/record_ogm.slim +5 -0
@@ 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"
M web.rb => web.rb +60 -9
@@ 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