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