customer_fwd.rb

  1# frozen_string_literal: true
  2
  3require "bandwidth"
  4require "value_semantics/monkey_patched"
  5require "uri"
  6
  7class CustomerFwd
  8	class InfiniteTimeout < StandardError
  9		attr_reader :fwd
 10
 11		def initialize(fwd)
 12			super "Infinite timeout"
 13			@fwd = fwd
 14		end
 15	end
 16
 17	def self.for(uri:, timeout: nil, voicemail_enabled: :default)
 18		timeout = Timeout.for(timeout, voicemail_enabled: voicemail_enabled)
 19
 20		fwd = if uri
 21			if uri =~ /\Asip:(.*)@sip.cheogram.com\Z/
 22				uri = "xmpp:#{$1.gsub(/%([0-9A-F]{2})/i) { $1.to_i(16).chr }}"
 23			end
 24
 25			URIS.fetch(uri.split(":", 2).first&.to_sym) {
 26				raise "Unknown forward URI: #{uri}"
 27			}.new(uri: uri, timeout: timeout)
 28		end
 29
 30		fwd && !timeout.zero? ? fwd : None.new(uri: uri, timeout: timeout)
 31	end
 32
 33	class Timeout
 34		def self.for(s, voicemail_enabled: :default)
 35			return Infinite.new unless voicemail_enabled
 36
 37			if s.nil? || s.is_a?(Infinite) || s.to_i.negative?
 38				return new(25) if voicemail_enabled == true # ~5s / ring, 5 rings
 39
 40				return Infinite.new
 41			end
 42
 43			return s if s.is_a?(self)
 44
 45			new(s)
 46		end
 47
 48		def initialize(s)
 49			@timeout = [s.to_i, 300].min
 50		end
 51
 52		def zero?
 53			@timeout.zero?
 54		end
 55
 56		def infinite?
 57			false
 58		end
 59
 60		def to_i
 61			@timeout
 62		end
 63
 64		def to_s
 65			to_i.to_s
 66		end
 67
 68		class Infinite < Timeout
 69			def initialize; end
 70
 71			def zero?
 72				false
 73			end
 74
 75			def infinite?
 76				1
 77			end
 78
 79			def to_i; end
 80		end
 81	end
 82
 83	value_semantics do
 84		uri Either(/:/, NilClass)
 85		def_attr :timeout, Timeout, coerce: Timeout.method(:for)
 86	end
 87
 88	def with(new_attrs)
 89		CustomerFwd.for(to_h.merge(new_attrs))
 90	end
 91
 92	def voicemail_enabled?
 93		!timeout.infinite?
 94	end
 95
 96	def create_call(account)
 97		raise InfiniteTimeout, self if timeout.infinite?
 98
 99		request = Bandwidth::ApiCreateCallRequest.new.tap { |cc|
100			cc.to = to
101			cc.call_timeout = timeout.to_i
102			yield cc if block_given?
103		}
104		BANDWIDTH_VOICE.create_call(account, body: request).data.call_id
105	end
106
107	class Tel < CustomerFwd
108		def initialize(values)
109			super
110			raise "Bad tel format: #{uri}" unless uri.match?(/\Atel:\+1\d{10}\Z/)
111		end
112
113		def to
114			uri.sub(/^tel:/, "")
115		end
116	end
117
118	class SIP < CustomerFwd
119		def to
120			uri
121		end
122	end
123
124	class XMPP < CustomerFwd
125		def to
126			jid = uri.sub(/^xmpp:/, "")
127			"sip:#{ERB::Util.url_encode(jid)}@sip.cheogram.com"
128		end
129	end
130
131	class None < CustomerFwd
132		def create_call(*); end
133
134		def to; end
135	end
136
137	URIS = {
138		tel: Tel,
139		sip: SIP,
140		xmpp: XMPP
141	}.freeze
142end