~singpolyma/sgx-jmp

aedc5f1390efc7abf0f5c6488fea5e1c19a46ea7 — Stephen Paul Weber 10 months ago f6896d1
Record Voicemail Greeting command
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