1# frozen_string_literal: true
2
3require "bandwidth"
4require "value_semantics/monkey_patched"
5require "uri"
6
7class CustomerFwd
8 def self.for(uri:, timeout:)
9 timeout = Timeout.new(timeout)
10
11 fwd = if uri
12 if uri =~ /\Asip:(.*)@sip.cheogram.com\Z/
13 uri = "xmpp:#{$1.gsub(/%([0-9A-F]{2})/i) { $1.to_i(16).chr }}"
14 end
15
16 URIS.fetch(uri.split(":", 2).first&.to_sym) {
17 raise "Unknown forward URI: #{uri}"
18 }.new(uri: uri, timeout: timeout)
19 end
20
21 fwd && !timeout.zero? ? fwd : None.new(uri: uri, timeout: timeout)
22 end
23
24 class Timeout
25 def self.new(s)
26 s.is_a?(self) ? s : super
27 end
28
29 def initialize(s)
30 @timeout = s.nil? || s.to_i.negative? || s.to_i > 300 ? 300 : s.to_i
31 end
32
33 def zero?
34 @timeout.zero?
35 end
36
37 def to_i
38 @timeout
39 end
40
41 def to_s
42 to_i.to_s
43 end
44 end
45
46 value_semantics do
47 uri Either(/:/, NilClass)
48 def_attr :timeout, Timeout, coerce: Timeout.method(:new)
49 end
50
51 def with(new_attrs)
52 CustomerFwd.for(to_h.merge(new_attrs))
53 end
54
55 def create_call(account)
56 request = Bandwidth::ApiCreateCallRequest.new.tap { |cc|
57 cc.to = to
58 cc.call_timeout = timeout.to_i
59 yield cc if block_given?
60 }
61 BANDWIDTH_VOICE.create_call(account, body: request).data.call_id
62 end
63
64 class Tel < CustomerFwd
65 def initialize(values)
66 super
67 raise "Bad tel format: #{uri}" unless uri.match?(/\Atel:\+1\d{10}\Z/)
68 end
69
70 def to
71 uri.sub(/^tel:/, "")
72 end
73 end
74
75 class SIP < CustomerFwd
76 def to
77 uri
78 end
79 end
80
81 class XMPP < CustomerFwd
82 def to
83 jid = uri.sub(/^xmpp:/, "")
84 "sip:#{ERB::Util.url_encode(jid)}@sip.cheogram.com"
85 end
86 end
87
88 class None < CustomerFwd
89 def create_call(*); end
90
91 def to; end
92 end
93
94 URIS = {
95 tel: Tel,
96 sip: SIP,
97 xmpp: XMPP
98 }.freeze
99end