M lib/backend_sgx.rb => lib/backend_sgx.rb +20 -51
@@ 1,71 1,40 @@
# frozen_string_literal: true
-class BackendSgx
- VOICEMAIL_TRANSCRIPTION_DISABLED = 0
+require "value_semantics/monkey_patched"
+
+require_relative "customer_fwd"
+require_relative "ibr"
+require_relative "not_loaded"
- def initialize(customer_id, jid=CONFIG[:sgx], creds=CONFIG[:creds])
- @customer_id = customer_id
- @jid = jid
- @creds = creds
+class BackendSgx
+ value_semantics do
+ jid Blather::JID
+ creds HashOf(Symbol => String)
+ from_jid Blather::JID
+ ogm_url Either(String, nil, NotLoaded)
+ fwd Either(CustomerFwd, nil, NotLoaded)
+ transcription_enabled Either(Bool(), NotLoaded)
+ registered? Either(IBR, FalseClass, NotLoaded)
end
def register!(tel)
- ibr = mkibr(:set)
- ibr.nick = @creds[:account]
- ibr.username = @creds[:username]
- ibr.password = @creds[:password]
+ ibr = IBR.new(:set, @jid)
+ ibr.from = from_jid
+ ibr.nick = creds[:account]
+ ibr.username = creds[:username]
+ ibr.password = creds[:password]
ibr.phone = tel
IQ_MANAGER.write(ibr)
end
- def registered?
- IQ_MANAGER.write(mkibr(:get)).catch { nil }.then do |result|
- if result&.respond_to?(:registered?) && result&.registered?
- result
- else
- false
- end
- end
- end
-
def stanza(s)
s.dup.tap do |stanza|
- stanza.to = stanza.to.with(domain: @jid)
+ stanza.to = stanza.to.with(domain: jid.domain)
stanza.from = from_jid.with(resource: stanza.from.resource)
end
end
- def ogm_url
- REDIS.get("catapult_ogm_url-#{from_jid}")
- end
-
- def catapult_flag(flagbit)
- REDIS.getbit(
- "catapult_setting_flags-#{from_jid}",
- flagbit
- ).then { |x| x == 1 }
- end
-
- def fwd_timeout
- REDIS.get("catapult_fwd_timeout-#{from_jid}")
- end
-
def set_fwd_timeout(timeout)
REDIS.set("catapult_fwd_timeout-#{from_jid}", timeout)
end
-
-protected
-
- def from_jid
- Blather::JID.new(
- "customer_#{@customer_id}",
- CONFIG[:component][:jid]
- )
- end
-
- def mkibr(type)
- ibr = IBR.new(type, @jid)
- ibr.from = from_jid
- ibr
- end
end
A lib/bwmsgsv2_repo.rb => lib/bwmsgsv2_repo.rb +63 -0
@@ 0,0 1,63 @@
+# frozen_string_literal: true
+
+require "lazy_object"
+
+require_relative "customer_fwd"
+require_relative "ibr"
+require_relative "trivial_backend_sgx_repo"
+
+class Bwmsgsv2Repo
+ VOICEMAIL_TRANSCRIPTION_DISABLED = 0
+
+ def initialize(jid: CONFIG[:sgx], redis: LazyObject.new { REDIS }, **kwargs)
+ @jid = jid
+ @redis = redis
+ @trivial_repo = TrivialBackendSgxRepo.new(jid: jid, **kwargs)
+ end
+
+ def get(customer_id)
+ sgx = @trivial_repo.get(customer_id)
+ 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),
+ transcription_enabled: !trans_d,
+ registered?: reg
+ }.compact)
+ end
+ end
+
+protected
+
+ def fetch_raw(from_jid)
+ registration(from_jid).then do |r|
+ EMPromise.all([from_redis(from_jid, r ? r.phone : nil), r])
+ end
+ end
+
+ def registration(from_jid)
+ ibr = IBR.new(:get, @jid)
+ ibr.from = from_jid
+
+ IQ_MANAGER.write(ibr).catch { nil }.then do |result|
+ if result&.respond_to?(:registered?) && result&.registered?
+ result
+ else
+ false
+ end
+ end
+ end
+
+ def from_redis(from_jid, tel)
+ EMPromise.all([
+ @redis.mget(*[
+ "catapult_ogm_url-#{from_jid}",
+ "catapult_fwd_timeout-#{from_jid}",
+ ("catapult_fwd-#{tel}" if tel)
+ ].compact),
+ @redis.getbit(
+ "catapult_setting_flags-#{from_jid}", VOICEMAIL_TRANSCRIPTION_DISABLED
+ ).then { |x| x == 1 }
+ ])
+ end
+end
M lib/command.rb => lib/command.rb +6 -6
@@ 53,7 53,7 @@ class Command
EMPromise.resolve(nil).then {
Thread.current[:execution] = self
sentry_hub
- catch_after(yield self)
+ catch_after(EMPromise.resolve(yield self))
}.catch(&method(:panic))
end
@@ 141,21 141,21 @@ class Command
def initialize(
node,
name,
+ customer_repo: CustomerRepo.new,
list_for: ->(tel:, **) { !!tel },
- format_error: ->(e) { e.respond_to?(:message) ? e.message : e.to_s },
- &blk
+ format_error: ->(e) { e.respond_to?(:message) ? e.message : e.to_s }
)
@node = node
@name = name
+ @customer_repo = customer_repo
@list_for = list_for
@format_error = format_error
- @blk = blk
+ @blk = ->(exe) { yield exe }
end
def register(blather, guards: [:execute?, node: @node, sessionid: nil])
blather.command(*guards) do |iq|
- customer_repo = CustomerRepo.new
- Execution.new(customer_repo, blather, @format_error, iq).execute(&@blk)
+ Execution.new(@customer_repo, blather, @format_error, iq).execute(&@blk)
end
self
end
M lib/command_list.rb => lib/command_list.rb +12 -12
@@ 9,22 9,22 @@ class CommandList
end
def self.for(customer)
- EMPromise.resolve(customer&.registered?).catch { nil }.then do |reg|
- args_for(customer, reg).then do |kwargs|
- new(@commands.select { |c| c.list_for?(**kwargs) })
- end
+ args_for(customer).then do |kwargs|
+ new(@commands.select { |c| c.list_for?(**kwargs) })
end
end
- def self.args_for(customer, reg)
- args = { customer: customer, tel: reg ? reg.phone : nil }
- return EMPromise.resolve(args) unless args[:tel]
+ def self.args_for(customer)
+ args = {
+ customer: customer,
+ tel: customer&.registered? ? customer&.registered?&.phone : nil,
+ fwd: customer&.fwd,
+ payment_methods: []
+ }
+ return EMPromise.resolve(args) unless customer&.plan_name
- EMPromise.all([
- REDIS.get("catapult_fwd-#{args[:tel]}"),
- customer.plan_name ? customer.payment_methods : []
- ]).then do |(fwd, payment_methods)|
- args.merge(fwd: fwd, payment_methods: payment_methods)
+ customer.payment_methods.then do |payment_methods|
+ args.merge(payment_methods: payment_methods)
end
end
M lib/customer.rb => lib/customer.rb +4 -5
@@ 14,6 14,7 @@ require_relative "./payment_methods"
require_relative "./plan"
require_relative "./proxied_jid"
require_relative "./sip_account"
+require_relative "./trivial_backend_sgx_repo"
class Customer
extend Forwardable
@@ 22,7 23,7 @@ class Customer
def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan,
:currency, :merchant_account, :plan_name, :auto_top_up_amount
def_delegators :@sgx, :register!, :registered?,
- :fwd_timeout, :set_fwd_timeout, :catapult_flag
+ :set_fwd_timeout, :fwd, :transcription_enabled
def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage
def initialize(
@@ 30,7 31,7 @@ class Customer
jid,
plan: CustomerPlan.new(customer_id),
balance: BigDecimal(0),
- sgx: BackendSgx.new(customer_id)
+ sgx: TrivialBackendSgxRepo.new.get(customer_id)
)
@plan = plan
@usage = CustomerUsage.new(customer_id)
@@ 83,9 84,7 @@ class Customer
end
def ogm(from_tel=nil)
- @sgx.ogm_url.then do |url|
- CustomerOGM.for(url, -> { fetch_vcard_temp(from_tel) })
- end
+ CustomerOGM.for(@sgx.ogm_url, -> { fetch_vcard_temp(from_tel) })
end
def sip_account
A lib/customer_fwd.rb => lib/customer_fwd.rb +72 -0
@@ 0,0 1,72 @@
+# frozen_string_literal: true
+
+require "uri"
+
+class CustomerFwd
+ def self.for(uri, timeout)
+ timeout = Timeout.new(timeout)
+ return if !uri || timeout.zero?
+ URIS.fetch(uri.split(":", 2).first.to_sym) {
+ raise "Unknown forward URI: #{uri}"
+ }.new(uri, timeout)
+ end
+
+ class Timeout
+ def initialize(s)
+ @timeout = s.nil? || s.to_i.negative? ? 300 : s.to_i
+ end
+
+ def zero?
+ @timeout.zero?
+ end
+
+ def to_i
+ @timeout
+ end
+ end
+
+ class Tel < CustomerFwd
+ attr_reader :timeout
+
+ def initialize(uri, timeout)
+ @tel = uri.sub(/^tel:/, "")
+ @timeout = timeout
+ end
+
+ def to
+ @tel
+ end
+ end
+
+ class SIP < CustomerFwd
+ attr_reader :timeout
+
+ def initialize(uri, timeout)
+ @uri = uri
+ @timeout = timeout
+ end
+
+ def to
+ @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"
+ end
+ end
+
+ URIS = {
+ tel: Tel,
+ sip: SIP,
+ xmpp: XMPP
+ }.freeze
+end
M lib/customer_info.rb => lib/customer_info.rb +2 -9
@@ 15,24 15,17 @@ class CustomerInfo
end
def self.for(customer, plan, expires_at)
- fetch_inputs(customer, plan).then do |(auto_top_up_amount, registration)|
+ plan.auto_top_up_amount.then do |auto_top_up_amount|
new(
plan: plan,
auto_top_up_amount: auto_top_up_amount,
- tel: registration ? registration.phone : nil,
+ tel: customer.registered? ? customer.regsitered?.phone : nil,
balance: customer.balance,
expires_at: expires_at
)
end
end
- def self.fetch_inputs(customer, plan)
- EMPromise.all([
- plan.auto_top_up_amount,
- customer.registered?
- ])
- end
-
def account_status
if plan.plan_name.nil?
"Transitional"
M lib/customer_info_form.rb => lib/customer_info_form.rb +2 -1
@@ 1,11 1,12 @@
# frozen_string_literal: true
+require_relative "bwmsgsv2_repo"
require_relative "customer_repo"
require_relative "proxied_jid"
require_relative "legacy_customer"
class CustomerInfoForm
- def initialize(customer_repo=CustomerRepo.new)
+ def initialize(customer_repo=CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new))
@customer_repo = customer_repo
end
M lib/customer_repo.rb => lib/customer_repo.rb +19 -5
@@ 1,14 1,22 @@
# frozen_string_literal: true
+require "lazy_object"
+
require_relative "customer"
require_relative "legacy_customer"
require_relative "polyfill"
class CustomerRepo
- def initialize(redis: REDIS, db: DB, braintree: BRAINTREE)
+ def initialize(
+ redis: LazyObject.new { REDIS },
+ db: LazyObject.new { DB },
+ braintree: LazyObject.new { BRAINTREE },
+ sgx_repo: TrivialBackendSgxRepo.new
+ )
@redis = redis
@db = db
@braintree = braintree
+ @sgx_repo = sgx_repo
end
def find(customer_id)
@@ 19,7 27,7 @@ class CustomerRepo
end
def find_by_jid(jid)
- if jid.to_s =~ /\Acustomer_(.+)@jmp.chat\Z/
+ if jid.to_s =~ /\Acustomer_(.+)@#{CONFIG[:component][:jid]}\Z/
find($1)
else
@redis.get("jmp_customer_id-#{jid}").then { |customer_id|
@@ 46,13 54,19 @@ class CustomerRepo
"jmp_customer_id-#{jid}", cid, "jmp_customer_jid-#{cid}", jid
).then do |redis_result|
raise "Saving new customer to redis failed" unless redis_result == 1
- Customer.new(cid, Blather::JID.new(jid))
+ Customer.new(cid, Blather::JID.new(jid), sgx: new_sgx(cid))
end
end
end
protected
+ def new_sgx(customer_id)
+ TrivialBackendSgxRepo.new.get(customer_id).with(
+ registered?: false
+ )
+ end
+
def find_legacy_customer(jid)
@redis.lindex("catapult_cred-#{jid}", 3).then do |tel|
raise "No customer" unless tel
@@ 76,9 90,9 @@ protected
FROM customer_plans LEFT JOIN balances USING (customer_id)
WHERE customer_id=$1 LIMIT 1
SQL
- result.then do |rows|
+ EMPromise.all([@sgx_repo.get(customer_id), result]).then do |(sgx, rows)|
data = hydrate_plan(customer_id, rows.first&.transform_keys(&:to_sym) || {})
- Customer.new(customer_id, Blather::JID.new(jid), **data)
+ Customer.new(customer_id, Blather::JID.new(jid), sgx: sgx, **data)
end
end
end
A lib/not_loaded.rb => lib/not_loaded.rb +17 -0
@@ 0,0 1,17 @@
+# frozen_string_literal: true
+
+class NotLoaded
+ class NotLoadedError < StandardError; end
+
+ def initialize(name)
+ @name = name
+ end
+
+ def respond_to_missing?(*)
+ true
+ end
+
+ def method_missing(*) # rubocop:disable Style/MethodMissing
+ raise NotLoadedError, "#{@name} not loaded"
+ end
+end
M lib/registration.rb => lib/registration.rb +5 -7
@@ 13,13 13,11 @@ require_relative "./tel_selections"
class Registration
def self.for(customer, tel_selections)
- customer.registered?.then do |registered|
- if registered
- Registered.new(registered.phone)
- else
- tel_selections[customer.jid].then(&:choose_tel).then do |tel|
- Activation.for(customer, tel)
- end
+ if (reg = customer.registered?)
+ Registered.new(reg.phone)
+ else
+ tel_selections[customer.jid].then(&:choose_tel).then do |tel|
+ Activation.for(customer, tel)
end
end
end
A lib/trivial_backend_sgx_repo.rb => lib/trivial_backend_sgx_repo.rb +28 -0
@@ 0,0 1,28 @@
+# frozen_string_literal: true
+
+require_relative "backend_sgx"
+require_relative "not_loaded"
+
+class TrivialBackendSgxRepo
+ def initialize(
+ jid: CONFIG[:sgx],
+ creds: CONFIG[:creds],
+ component_jid: CONFIG[:component][:jid]
+ )
+ @jid = Blather::JID.new(jid)
+ @creds = creds
+ @component_jid = component_jid
+ end
+
+ def get(customer_id)
+ BackendSgx.new(
+ jid: @jid,
+ creds: @creds,
+ from_jid: Blather::JID.new("customer_#{customer_id}", @component_jid),
+ ogm_url: NotLoaded.new(:ogm_url),
+ fwd: NotLoaded.new(:fwd_timeout),
+ transcription_enabled: NotLoaded.new(:transcription_enabled),
+ registered?: NotLoaded.new(:registered?)
+ )
+ end
+end
M sgx_jmp.rb => sgx_jmp.rb +20 -11
@@ 1,6 1,7 @@
# frozen_string_literal: true
require "pg/em/connection_pool"
+require "bandwidth"
require "bigdecimal"
require "blather/client/dsl" # Require this first to not auto-include
require "blather/client"
@@ 68,6 69,7 @@ require_relative "lib/polyfill"
require_relative "lib/alt_top_up_form"
require_relative "lib/add_bitcoin_address"
require_relative "lib/backend_sgx"
+require_relative "lib/bwmsgsv2_repo"
require_relative "lib/bandwidth_tn_order"
require_relative "lib/btc_sell_prices"
require_relative "lib/buy_account_credit_form"
@@ 100,6 102,10 @@ BandwidthIris::Client.global_options = {
username: CONFIG[:creds][:username],
password: CONFIG[:creds][:password]
}
+BANDWIDTH_VOICE = Bandwidth::Client.new(
+ voice_basic_auth_user_name: CONFIG[:creds][:username],
+ voice_basic_auth_password: CONFIG[:creds][:password]
+).voice_client.client
def new_sentry_hub(stanza, name: nil)
hub = Sentry.get_current_hub&.new_from_top
@@ 200,7 206,7 @@ when_ready do
self << ping
end
- Web.run(LOG.child, CustomerRepo.new, *WEB_LISTEN)
+ Web.run(LOG.child, *WEB_LISTEN)
end
# workqueue_count MUST be 0 or else Blather uses threads!
@@ 258,9 264,7 @@ message(
&.find { |el| el["jid"].to_s.start_with?("customer_") }
pass unless address
- CustomerRepo.new.find(
- Blather::JID.new(address["jid"].to_s).node.delete_prefix("customer_")
- ).then { |customer|
+ CustomerRepo.new.find_by_jid(address["jid"]).then { |customer|
m.from = m.from.with(domain: CONFIG[:component][:jid])
m.to = m.to.with(domain: customer.jid.domain)
address["jid"] = customer.jid.to_s
@@ 362,7 366,9 @@ disco_items node: "http://jabber.org/protocol/commands" do |iq|
reply = iq.reply
reply.node = "http://jabber.org/protocol/commands"
- CustomerRepo.new.find_by_jid(iq.from.stripped).catch {
+ CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new).find_by_jid(
+ iq.from.stripped
+ ).catch {
nil
}.then { |customer|
CommandList.for(customer)
@@ 397,7 403,8 @@ end
Command.new(
"jabber:iq:register",
"Register",
- list_for: ->(*) { true }
+ list_for: ->(*) { true },
+ customer_repo: CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new)
) {
Command.customer.catch {
Sentry.add_breadcrumb(Sentry::Breadcrumb.new(message: "Customer.create"))
@@ 542,7 549,8 @@ Command.new(
Command.new(
"info",
"Show Account Info",
- list_for: ->(*) { true }
+ list_for: ->(*) { true },
+ customer_repo: CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new)
) {
Command.customer.then(&:info).then do |info|
Command.finish do |reply|
@@ 584,17 592,18 @@ Command.new(
Command.new(
"migrate billing",
"Switch from PayPal or expired trial to new billing",
- list_for: ->(tel:, customer:, **) { tel && !customer&.currency }
+ list_for: ->(tel:, customer:, **) { tel && !customer&.currency },
+ customer_repo: CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new)
) {
EMPromise.all([
- Command.customer.then { |c| EMPromise.all([c, c.registered?.then(&:phone)]) },
+ Command.customer,
Command.reply do |reply|
reply.allowed_actions = [:next]
reply.command << FormTemplate.render("migrate_billing")
end
- ]).then do |((customer, tel), iq)|
+ ]).then do |(customer, iq)|
Registration::Payment.for(
- iq, customer, tel,
+ iq, customer, customer.registered?.phone,
final_message: PaypalDone::MESSAGE,
finish: PaypalDone
).then(&:write).catch_only(Command::Execution::FinalStanza) do |s|
M test/test_backend_sgx.rb => test/test_backend_sgx.rb +11 -9
@@ 1,17 1,16 @@
# frozen_string_literal: true
require "test_helper"
+require "bwmsgsv2_repo"
require "backend_sgx"
+require "trivial_backend_sgx_repo"
BackendSgx::IQ_MANAGER = Minitest::Mock.new
+Bwmsgsv2Repo::IQ_MANAGER = Minitest::Mock.new
class BackendSgxTest < Minitest::Test
- def setup
- @sgx = BackendSgx.new("test")
- end
-
def test_registered
- BackendSgx::IQ_MANAGER.expect(
+ Bwmsgsv2Repo::IQ_MANAGER.expect(
:write,
EMPromise.resolve(IBR.new.tap { |ibr| ibr.registered = true }),
[Matching.new do |ibr|
@@ 19,12 18,13 @@ class BackendSgxTest < Minitest::Test
assert_equal "customer_test@component", ibr.from.to_s
end]
)
- assert @sgx.registered?.sync
+ sgx = Bwmsgsv2Repo.new(redis: FakeRedis.new).get("test").sync
+ assert sgx.registered?
end
em :test_registered
def test_registered_not_registered
- BackendSgx::IQ_MANAGER.expect(
+ Bwmsgsv2Repo::IQ_MANAGER.expect(
:write,
EMPromise.resolve(IBR.new.tap { |ibr| ibr.registered = false }),
[Matching.new do |ibr|
@@ 32,7 32,8 @@ class BackendSgxTest < Minitest::Test
assert_equal "customer_test@component", ibr.from.to_s
end]
)
- refute @sgx.registered?.sync
+ sgx = Bwmsgsv2Repo.new(redis: FakeRedis.new).get("test").sync
+ refute sgx.registered?
end
em :test_registered_not_registered
@@ 48,7 49,8 @@ class BackendSgxTest < Minitest::Test
assert_equal "+15555550000", ibr.phone
end]
)
- @sgx.register!("+15555550000")
+ sgx = TrivialBackendSgxRepo.new.get("test")
+ sgx.register!("+15555550000")
BackendSgx::IQ_MANAGER.verify
end
end
M test/test_command_list.rb => test/test_command_list.rb +5 -21
@@ 6,6 6,9 @@ require "command_list"
CommandList::Customer = Minitest::Mock.new
CommandList::REDIS = Minitest::Mock.new
+CustomerRepo::REDIS = Minitest::Mock.new
+CustomerRepo::DB = Minitest::Mock.new
+CustomerRepo::BRAINTREE = Minitest::Mock.new
class CommandListTest < Minitest::Test
SETUP = begin
@@ 44,11 47,6 @@ class CommandListTest < Minitest::Test
em :test_for_unregistered
def test_for_registered
- CommandList::REDIS.expect(
- :get,
- EMPromise.resolve(nil),
- ["catapult_fwd-1"]
- )
customer = OpenStruct.new(
registered?: OpenStruct.new(phone: "1"),
payment_methods: EMPromise.resolve([])
@@ 61,14 59,10 @@ class CommandListTest < Minitest::Test
em :test_for_registered
def test_for_registered_with_fwd
- CommandList::REDIS.expect(
- :get,
- EMPromise.resolve("tel:1"),
- ["catapult_fwd-1"]
- )
customer = OpenStruct.new(
registered?: OpenStruct.new(phone: "1"),
- payment_methods: EMPromise.resolve([])
+ payment_methods: EMPromise.resolve([]),
+ fwd: OpenStruct.new
)
assert_equal(
["no_customer", "registered", "fwd"],
@@ 78,11 72,6 @@ class CommandListTest < Minitest::Test
em :test_for_registered_with_fwd
def test_for_registered_with_credit_card
- CommandList::REDIS.expect(
- :get,
- EMPromise.resolve(nil),
- ["catapult_fwd-1"]
- )
customer = OpenStruct.new(
registered?: OpenStruct.new(phone: "1"),
plan_name: "test",
@@ 96,11 85,6 @@ class CommandListTest < Minitest::Test
em :test_for_registered_with_credit_card
def test_for_registered_with_currency
- CommandList::REDIS.expect(
- :get,
- EMPromise.resolve(nil),
- ["catapult_fwd-1"]
- )
customer = OpenStruct.new(
registered?: OpenStruct.new(phone: "1"),
currency: :USD
M test/test_customer_info.rb => test/test_customer_info.rb +4 -4
@@ 9,7 9,7 @@ CustomerPlan::REDIS = Minitest::Mock.new
class CustomerInfoTest < Minitest::Test
def test_info_does_not_crash
sgx = Minitest::Mock.new
- sgx.expect(:registered?, EMPromise.resolve(nil))
+ sgx.expect(:registered?, false)
CustomerPlan::REDIS.expect(
:get,
@@ 25,7 25,7 @@ class CustomerInfoTest < Minitest::Test
def test_admin_info_does_not_crash
sgx = Minitest::Mock.new
- sgx.expect(:registered?, EMPromise.resolve(nil))
+ sgx.expect(:registered?, false)
CustomerPlan::REDIS.expect(
:get,
@@ 41,7 41,7 @@ class CustomerInfoTest < Minitest::Test
def test_inactive_info_does_not_crash
sgx = Minitest::Mock.new
- sgx.expect(:registered?, EMPromise.resolve(nil))
+ sgx.expect(:registered?, false)
CustomerPlan::REDIS.expect(
:get,
@@ 63,7 63,7 @@ class CustomerInfoTest < Minitest::Test
def test_inactive_admin_info_does_not_crash
sgx = Minitest::Mock.new
- sgx.expect(:registered?, EMPromise.resolve(nil))
+ sgx.expect(:registered?, false)
CustomerPlan::REDIS.expect(
:get,
M test/test_customer_repo.rb => test/test_customer_repo.rb +5 -5
@@ 8,15 8,15 @@ class CustomerRepoTest < Minitest::Test
# sgx-jmp customer
"jmp_customer_jid-test" => "test@example.com",
"jmp_customer_id-test@example.com" => "test",
- "catapult_jid-+13334445555" => "customer_test@jmp.chat",
- "catapult_cred-customer_test@jmp.chat" => [
+ "catapult_jid-+13334445555" => "customer_test@component",
+ "catapult_cred-customer_test@component" => [
"test_bw_customer", "", "", "+13334445555"
],
# sgx-jmp customer, empty DB
"jmp_customer_jid-empty" => "empty@example.com",
"jmp_customer_id-empty@example.com" => "empty",
- "catapult_jid-+16667778888" => "customer_empty@jmp.chat",
- "catapult_cred-customer_empty@jmp.chat" => [
+ "catapult_jid-+16667778888" => "customer_empty@component",
+ "catapult_cred-customer_empty@component" => [
"test_bw_customer", "", "", "+16667778888"
],
# v2 customer
@@ 75,7 75,7 @@ class CustomerRepoTest < Minitest::Test
em :test_find_by_id
def test_find_by_customer_jid
- customer = @repo.find_by_jid("customer_test@jmp.chat").sync
+ customer = @repo.find_by_jid("customer_test@component").sync
assert_kind_of Customer, customer
assert_equal 1234, customer.balance
assert_equal "merchant_usd", customer.merchant_account
M test/test_helper.rb => test/test_helper.rb +8 -0
@@ 168,10 168,18 @@ class FakeRedis
set(key, value)
end
+ def mget(*keys)
+ EMPromise.all(keys.map(&method(:get)))
+ end
+
def get(key)
EMPromise.resolve(@values[key])
end
+ def getbit(key, bit)
+ get(key).then { |v| v.to_i.to_s(2)[bit].to_i }
+ end
+
def exists(*keys)
EMPromise.resolve(
@values.select { |k, _| keys.include? k }.size
M test/test_registration.rb => test/test_registration.rb +4 -4
@@ 20,7 20,7 @@ end
class RegistrationTest < Minitest::Test
def test_for_registered
sgx = OpenStruct.new(
- registered?: EMPromise.resolve(OpenStruct.new(phone: "+15555550000"))
+ registered?: OpenStruct.new(phone: "+15555550000")
)
iq = Blather::Stanza::Iq::Command.new
iq.from = "test@example.com"
@@ 38,7 38,7 @@ class RegistrationTest < Minitest::Test
web_manager = TelSelections.new(redis: FakeRedis.new)
web_manager.set("test@example.net", "+15555550000")
result = execute_command do
- sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
+ sgx = OpenStruct.new(registered?: false)
Registration.for(
customer(
plan_name: "test_usd",
@@ 53,7 53,7 @@ class RegistrationTest < Minitest::Test
em :test_for_activated
def test_for_not_activated_with_customer_id
- sgx = OpenStruct.new(registered?: EMPromise.resolve(nil))
+ sgx = OpenStruct.new(registered?: false)
web_manager = TelSelections.new(redis: FakeRedis.new)
web_manager.set("test@example.net", "+15555550000")
iq = Blather::Stanza::Iq::Command.new
@@ 520,7 520,7 @@ class RegistrationTest < Minitest::Test
BackendSgx::REDIS = Minitest::Mock.new
def setup
- @sgx = Minitest::Mock.new(BackendSgx.new("test"))
+ @sgx = Minitest::Mock.new(TrivialBackendSgxRepo.new.get("test"))
iq = Blather::Stanza::Iq::Command.new
iq.from = "test\\40example.com@cheogram.com"
@finish = Registration::Finish.new(
M web.rb => web.rb +30 -125
@@ 5,99 5,12 @@ require "forwardable"
require "roda"
require "thin"
require "sentry-ruby"
-require "bandwidth"
-
-Faraday.default_adapter = :em_synchrony
require_relative "lib/cdr"
require_relative "lib/roda_capture"
require_relative "lib/roda_em_promise"
require_relative "lib/rack_fiber"
-BANDWIDTH_VOICE = Bandwidth::Client.new(
- voice_basic_auth_user_name: CONFIG[:creds][:username],
- voice_basic_auth_password: CONFIG[:creds][:password]
-).voice_client.client
-
-module CustomerFwd
- def self.from_redis(redis, customer, tel)
- EMPromise.all([
- redis.get("catapult_fwd-#{tel}"),
- customer.fwd_timeout
- ]).then do |(fwd, stimeout)|
- timeout = Timeout.new(stimeout)
- next if !fwd || timeout.zero?
- self.for(fwd, timeout)
- end
- end
-
- def self.for(uri, timeout)
- case uri
- when /^tel:/
- Tel.new(uri, timeout)
- when /^sip:/
- SIP.new(uri, timeout)
- when /^xmpp:/
- XMPP.new(uri, timeout)
- else
- raise "Unknown forward URI: #{uri}"
- end
- end
-
- class Timeout
- def initialize(s)
- @timeout = s.nil? || s.to_i.negative? ? 300 : s.to_i
- end
-
- def zero?
- @timeout.zero?
- end
-
- def to_i
- @timeout
- end
- end
-
- class Tel
- attr_reader :timeout
-
- def initialize(uri, timeout)
- @tel = uri.sub(/^tel:/, "")
- @timeout = timeout
- end
-
- def to
- @tel
- end
- end
-
- class SIP
- attr_reader :timeout
-
- def initialize(uri, timeout)
- @uri = uri
- @timeout = timeout
- end
-
- def to
- @uri
- end
- end
-
- class XMPP
- 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"
- end
- end
-end
-
# rubocop:disable Metrics/ClassLength
class Web < Roda
use Rack::Fiber # Must go first!
@@ 112,9 25,8 @@ class Web < Roda
attr_reader :customer_repo, :log
attr_reader :true_inbound_call, :outbound_transfers
- def run(log, customer_repo, *listen_on)
+ def run(log, *listen_on)
plugin :common_logger, log, method: :info
- @customer_repo = customer_repo
@true_inbound_call = {}
@outbound_transfers = {}
Thin::Logging.logger = log
@@ 127,8 39,7 @@ class Web < Roda
end
extend Forwardable
- def_delegators :'self.class', :customer_repo, :true_inbound_call,
- :outbound_transfers
+ def_delegators :'self.class', :true_inbound_call, :outbound_transfers
def_delegators :request, :params
def log
@@ 221,7 132,7 @@ class Web < Roda
end
end
- customer_repo.find_by_tel(params["to"]).then do |customer|
+ CustomerRepo.new.find_by_tel(params["to"]).then do |customer|
CDR.for_inbound(customer.customer_id, params).save
end
}.catch(&method(:log_error))
@@ 257,7 168,7 @@ class Web < Roda
"https://jmp.chat"
)
- customer_repo.find_by_tel(params["to"]).then do |customer|
+ CustomerRepo.new.find_by_tel(params["to"]).then do |customer|
m = Blather::Stanza::Message.new
m.chat_state = nil
m.from = from_jid
@@ 271,7 182,7 @@ class Web < Roda
end
r.post "transcription" do
- customer_repo.find_by_tel(params["to"]).then do |customer|
+ CustomerRepo.new.find_by_tel(params["to"]).then do |customer|
m = Blather::Stanza::Message.new
m.chat_state = nil
m.from = from_jid
@@ 286,19 197,13 @@ class Web < Roda
end
r.post do
- customer_repo
+ CustomerRepo
+ .new(sgx_repo: Bwmsgsv2Repo.new)
.find_by_tel(params["to"])
- .then { |customer|
- EMPromise.all([
- customer.ogm(params["from"]),
- customer.catapult_flag(
- BackendSgx::VOICEMAIL_TRANSCRIPTION_DISABLED
- )
- ])
- }.then do |(ogm, transcription_disabled)|
+ .then do |customer|
render :voicemail, locals: {
- ogm: ogm,
- transcription_enabled: !transcription_disabled
+ ogm: customer.ogm(params["from"]),
+ transcription_enabled: customer.transcription_enabled
}
end
end
@@ 316,25 221,25 @@ class Web < Roda
return render :pause, locals: { duration: 300 }
end
- customer_repo.find_by_tel(params["to"]).then do |customer|
- CustomerFwd.from_redis(::REDIS, customer, params["to"]).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
- ).data.call_id
- render :pause, locals: { duration: 300 }
- else
- render :redirect, locals: { to: inbound_calls_path(:voicemail) }
+ CustomerRepo.new(
+ 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
+ ).data.call_id
+ render :pause, locals: { duration: 300 }
+ else
+ render :redirect, locals: { to: inbound_calls_path(:voicemail) }
end
end
end
@@ 353,9 258,9 @@ class Web < Roda
r.post do
customer_id = params["from"].sub(/^\+1/, "")
- customer_repo.find(customer_id).then(:registered?).then do |reg|
+ CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new).find(customer_id).then do |c|
render :forward, locals: {
- from: reg.phone,
+ from: c.registered?.phone,
to: params["to"]
}
end