vonage 7.2.1 → 7.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +46 -1
- data/lib/vonage/abstract_authentication.rb +1 -1
- data/lib/vonage/applications/list_response.rb +1 -1
- data/lib/vonage/applications.rb +11 -3
- data/lib/vonage/basic.rb +1 -1
- data/lib/vonage/bearer_token.rb +1 -1
- data/lib/vonage/config.rb +1 -1
- data/lib/vonage/conversations/events.rb +6 -2
- data/lib/vonage/conversations/legs.rb +6 -2
- data/lib/vonage/conversations/members.rb +6 -2
- data/lib/vonage/conversations/users.rb +6 -2
- data/lib/vonage/conversations.rb +10 -3
- data/lib/vonage/entity.rb +0 -2
- data/lib/vonage/form_data.rb +1 -1
- data/lib/vonage/gsm7.rb +4 -1
- data/lib/vonage/json.rb +1 -1
- data/lib/vonage/jwt.rb +1 -1
- data/lib/vonage/namespace.rb +121 -16
- data/lib/vonage/numbers/list_response.rb +1 -1
- data/lib/vonage/numbers/response.rb +2 -2
- data/lib/vonage/numbers.rb +9 -1
- data/lib/vonage/params.rb +1 -1
- data/lib/vonage/response.rb +1 -0
- data/lib/vonage/secrets/list_response.rb +1 -1
- data/lib/vonage/secrets.rb +6 -2
- data/lib/vonage/user_agent.rb +4 -1
- data/lib/vonage/verify.rb +1 -1
- data/lib/vonage/version.rb +1 -1
- data/lib/vonage/voice/actions/connect.rb +199 -0
- data/lib/vonage/voice/actions/conversation.rb +107 -0
- data/lib/vonage/voice/actions/input.rb +119 -0
- data/lib/vonage/voice/actions/notify.rb +57 -0
- data/lib/vonage/voice/actions/record.rb +130 -0
- data/lib/vonage/voice/actions/stream.rb +72 -0
- data/lib/vonage/voice/actions/talk.rb +73 -0
- data/lib/vonage/voice/list_response.rb +1 -1
- data/lib/vonage/voice/ncco.rb +42 -0
- data/lib/vonage/voice.rb +9 -1
- data/vonage.gemspec +2 -0
- metadata +39 -3
@@ -0,0 +1,199 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'phonelib'
|
4
|
+
|
5
|
+
module Vonage
|
6
|
+
class Voice::Actions::Connect
|
7
|
+
attr_accessor :endpoint, :from, :eventType, :timeout, :limit, :machineDetection, :eventUrl, :eventMethod, :ringbackTone
|
8
|
+
|
9
|
+
def initialize(attributes = {})
|
10
|
+
@endpoint = attributes.fetch(:endpoint)
|
11
|
+
@from = attributes.fetch(:from, nil)
|
12
|
+
@eventType = attributes.fetch(:eventType, nil)
|
13
|
+
@timeout = attributes.fetch(:timeout, nil)
|
14
|
+
@limit = attributes.fetch(:limit, nil)
|
15
|
+
@machineDetection = attributes.fetch(:machineDetection, nil)
|
16
|
+
@eventUrl = attributes.fetch(:eventUrl, nil)
|
17
|
+
@eventMethod = attributes.fetch(:eventMethod, nil)
|
18
|
+
@ringbackTone = attributes.fetch(:ringbackTone, nil)
|
19
|
+
|
20
|
+
after_initialize!
|
21
|
+
end
|
22
|
+
|
23
|
+
def after_initialize!
|
24
|
+
verify_endpoint
|
25
|
+
|
26
|
+
if self.from
|
27
|
+
verify_from
|
28
|
+
end
|
29
|
+
|
30
|
+
if self.eventType
|
31
|
+
verify_event_type
|
32
|
+
end
|
33
|
+
|
34
|
+
if self.limit
|
35
|
+
verify_limit
|
36
|
+
end
|
37
|
+
|
38
|
+
if self.machineDetection
|
39
|
+
verify_machine_detection
|
40
|
+
end
|
41
|
+
|
42
|
+
if self.eventUrl
|
43
|
+
verify_event_url
|
44
|
+
end
|
45
|
+
|
46
|
+
if self.eventMethod
|
47
|
+
verify_event_method
|
48
|
+
end
|
49
|
+
|
50
|
+
if self.ringbackTone
|
51
|
+
verify_ringback_tone
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def verify_endpoint
|
56
|
+
case self.endpoint[:type]
|
57
|
+
when 'phone'
|
58
|
+
raise ClientError.new("Expected 'number' value to be in E.164 format") unless Phonelib.parse(endpoint[:number].to_i).valid?
|
59
|
+
when 'app'
|
60
|
+
raise ClientError.new("'user' must be defined") unless endpoint[:user]
|
61
|
+
when 'websocket'
|
62
|
+
raise ClientError.new("Expected 'uri' value to be a valid URI") unless URI.parse(endpoint[:uri]).kind_of?(URI::Generic)
|
63
|
+
raise ClientError.new("Expected 'content-type' parameter to be either 'audio/116;rate=16000' or 'audio/116;rate=8000") unless endpoint[:'content-type'] == 'audio/116;rate=16000' || endpoint[:'content-type'] == 'audio/116;rate=8000'
|
64
|
+
when 'sip'
|
65
|
+
raise ClientError.new("Expected 'uri' value to be a valid URI") unless URI.parse(endpoint[:uri]).kind_of?(URI::Generic)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def verify_from
|
70
|
+
raise ClientError.new("Invalid 'from' value, must be in E.164 format") unless Phonelib.parse(self.from.to_i).valid?
|
71
|
+
end
|
72
|
+
|
73
|
+
def verify_event_type
|
74
|
+
raise ClientError.new("Invalid 'eventType' value, must be 'synchronous' if defined") unless self.eventType == 'synchronous'
|
75
|
+
end
|
76
|
+
|
77
|
+
def verify_limit
|
78
|
+
raise ClientError.new("Invalid 'limit' value, must be between 0 and 7200 seconds") unless self.limit.to_i >= 0 && self.limit.to_i <= 7200
|
79
|
+
end
|
80
|
+
|
81
|
+
def verify_machine_detection
|
82
|
+
raise ClientError.new("Invalid 'machineDetection' value, must be either: 'continue' or 'hangup' if defined") unless self.machineDetection == 'continue' || self.machineDetection == 'hangup'
|
83
|
+
end
|
84
|
+
|
85
|
+
def verify_event_url
|
86
|
+
uri = URI.parse(self.eventUrl)
|
87
|
+
|
88
|
+
raise ClientError.new("Invalid 'eventUrl' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
89
|
+
|
90
|
+
self.eventUrl
|
91
|
+
end
|
92
|
+
|
93
|
+
def verify_event_method
|
94
|
+
valid_methods = ['GET', 'POST']
|
95
|
+
|
96
|
+
raise ClientError.new("Invalid 'eventMethod' value. must be either: 'GET' or 'POST'") unless valid_methods.include?(self.eventMethod.upcase)
|
97
|
+
end
|
98
|
+
|
99
|
+
def verify_ringback_tone
|
100
|
+
uri = URI.parse(self.ringbackTone)
|
101
|
+
|
102
|
+
raise ClientError.new("Invalid 'ringbackTone' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
103
|
+
|
104
|
+
self.ringbackTone
|
105
|
+
end
|
106
|
+
|
107
|
+
def action
|
108
|
+
create_connect!(self)
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_connect!(builder)
|
112
|
+
ncco = [
|
113
|
+
{
|
114
|
+
action: 'connect',
|
115
|
+
endpoint: [
|
116
|
+
create_endpoint(builder)
|
117
|
+
]
|
118
|
+
}
|
119
|
+
]
|
120
|
+
|
121
|
+
ncco[0].merge!(from: builder.from) if builder.from
|
122
|
+
ncco[0].merge!(eventType: builder.eventType) if builder.eventType
|
123
|
+
ncco[0].merge!(timeout: builder.timeout) if builder.timeout
|
124
|
+
ncco[0].merge!(limit: builder.limit) if builder.limit
|
125
|
+
ncco[0].merge!(machineDetection: builder.machineDetection) if builder.machineDetection
|
126
|
+
ncco[0].merge!(eventUrl: builder.eventUrl) if builder.eventUrl
|
127
|
+
ncco[0].merge!(eventMethod: builder.eventMethod) if builder.eventMethod
|
128
|
+
ncco[0].merge!(ringbackTone: builder.ringbackTone) if builder.ringbackTone
|
129
|
+
|
130
|
+
ncco
|
131
|
+
end
|
132
|
+
|
133
|
+
def create_endpoint(builder)
|
134
|
+
case builder.endpoint[:type]
|
135
|
+
when 'phone'
|
136
|
+
phone_endpoint(builder.endpoint)
|
137
|
+
when 'app'
|
138
|
+
app_endpoint(builder.endpoint)
|
139
|
+
when 'websocket'
|
140
|
+
websocket_endpoint(builder.endpoint)
|
141
|
+
when 'sip'
|
142
|
+
sip_endpoint(builder.endpoint)
|
143
|
+
when 'vbc'
|
144
|
+
vbc_endpoint(builder.endpoint)
|
145
|
+
else
|
146
|
+
raise ClientError.new("Invalid value for 'endpoint', please refer to the Vonage API Developer Portal https://developer.nexmo.com/voice/voice-api/ncco-reference#endpoint-types-and-values for a list of possible values")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def phone_endpoint(endpoint_attrs)
|
151
|
+
hash = {
|
152
|
+
type: 'phone',
|
153
|
+
number: endpoint_attrs[:number]
|
154
|
+
}
|
155
|
+
|
156
|
+
hash.merge!(dtmfAnswer: endpoint_attrs[:dtmfAnswer]) if endpoint_attrs[:dtmfAnswer]
|
157
|
+
hash.merge!(onAnswer: endpoint_attrs[:onAnswer]) if endpoint_attrs[:onAnswer]
|
158
|
+
|
159
|
+
hash
|
160
|
+
end
|
161
|
+
|
162
|
+
def app_endpoint(endpoint_attrs)
|
163
|
+
{
|
164
|
+
type: 'app',
|
165
|
+
user: endpoint_attrs[:user]
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
def websocket_endpoint(endpoint_attrs)
|
170
|
+
hash = {
|
171
|
+
type: 'websocket',
|
172
|
+
uri: endpoint_attrs[:uri],
|
173
|
+
:'content-type' => endpoint_attrs[:'content-type']
|
174
|
+
}
|
175
|
+
|
176
|
+
hash.merge!(headers: endpoint_attrs[:headers]) if endpoint_attrs[:headers]
|
177
|
+
|
178
|
+
hash
|
179
|
+
end
|
180
|
+
|
181
|
+
def sip_endpoint(endpoint_attrs)
|
182
|
+
hash = {
|
183
|
+
type: 'sip',
|
184
|
+
uri: endpoint_attrs[:uri]
|
185
|
+
}
|
186
|
+
|
187
|
+
hash.merge!(headers: endpoint_attrs[:headers]) if endpoint_attrs[:headers]
|
188
|
+
|
189
|
+
hash
|
190
|
+
end
|
191
|
+
|
192
|
+
def vbc_endpoint(endpoint_attrs)
|
193
|
+
{
|
194
|
+
type: 'vbc',
|
195
|
+
extension: endpoint_attrs[:extension]
|
196
|
+
}
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Voice::Actions::Conversation
|
6
|
+
attr_accessor :name, :musicOnHoldUrl, :startOnEnter, :endOnExit, :record, :canSpeak, :canHear, :mute
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
@name = attributes.fetch(:name)
|
10
|
+
@musicOnHoldUrl = attributes.fetch(:musicOnHoldUrl, nil)
|
11
|
+
@startOnEnter = attributes.fetch(:startOnEnter, nil)
|
12
|
+
@endOnExit = attributes.fetch(:endOnExit, nil)
|
13
|
+
@record = attributes.fetch(:record, nil)
|
14
|
+
@canSpeak = attributes.fetch(:canSpeak, nil)
|
15
|
+
@canHear = attributes.fetch(:canHear, nil)
|
16
|
+
@mute = attributes.fetch(:mute, nil)
|
17
|
+
|
18
|
+
after_initialize!
|
19
|
+
end
|
20
|
+
|
21
|
+
def after_initialize!
|
22
|
+
if self.musicOnHoldUrl
|
23
|
+
verify_music_on_hold_url
|
24
|
+
end
|
25
|
+
|
26
|
+
if self.startOnEnter
|
27
|
+
verify_start_on_enter
|
28
|
+
end
|
29
|
+
|
30
|
+
if self.endOnExit
|
31
|
+
verify_end_on_exit
|
32
|
+
end
|
33
|
+
|
34
|
+
if self.record
|
35
|
+
verify_record
|
36
|
+
end
|
37
|
+
|
38
|
+
if self.canSpeak
|
39
|
+
verify_can_speak
|
40
|
+
end
|
41
|
+
|
42
|
+
if self.canHear
|
43
|
+
verify_can_hear
|
44
|
+
end
|
45
|
+
|
46
|
+
if self.mute
|
47
|
+
verify_mute
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def verify_music_on_hold_url
|
52
|
+
uri = URI.parse(self.musicOnHoldUrl)
|
53
|
+
|
54
|
+
raise ClientError.new("Invalid 'musicOnHoldUrl' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
55
|
+
|
56
|
+
self.musicOnHoldUrl
|
57
|
+
end
|
58
|
+
|
59
|
+
def verify_start_on_enter
|
60
|
+
raise ClientError.new("Expected 'startOnEnter' value to be a Boolean") unless self.startOnEnter == true || self.startOnEnter == false
|
61
|
+
end
|
62
|
+
|
63
|
+
def verify_end_on_exit
|
64
|
+
raise ClientError.new("Expected 'endOnExit' value to be a Boolean") unless self.endOnExit == true || self.endOnExit == false
|
65
|
+
end
|
66
|
+
|
67
|
+
def verify_record
|
68
|
+
raise ClientError.new("Expected 'record' value to be a Boolean") unless self.record == true || self.record == false
|
69
|
+
end
|
70
|
+
|
71
|
+
def verify_can_speak
|
72
|
+
raise ClientError.new("Expected 'canSpeak' value to be an Array of leg UUIDs") unless self.canSpeak.is_a?(Array)
|
73
|
+
end
|
74
|
+
|
75
|
+
def verify_can_hear
|
76
|
+
raise ClientError.new("Expected 'canHear' value to be an Array of leg UUIDs") unless self.canHear.is_a?(Array)
|
77
|
+
end
|
78
|
+
|
79
|
+
def verify_mute
|
80
|
+
raise ClientError.new("Expected 'mute' value to be a Boolean") unless self.mute == true || self.mute == false
|
81
|
+
raise ClientError.new("The 'mute' value is not supported if the 'canSpeak' option is defined") if self.canSpeak
|
82
|
+
end
|
83
|
+
|
84
|
+
def action
|
85
|
+
create_conversation!(self)
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_conversation!(builder)
|
89
|
+
ncco = [
|
90
|
+
{
|
91
|
+
action: 'conversation',
|
92
|
+
name: builder.name
|
93
|
+
}
|
94
|
+
]
|
95
|
+
|
96
|
+
ncco[0].merge!(musicOnHoldUrl: builder.musicOnHoldUrl) if (builder.musicOnHoldUrl || builder.musicOnHoldUrl == false)
|
97
|
+
ncco[0].merge!(startOnEnter: builder.startOnEnter) if (builder.startOnEnter || builder.startOnEnter == false)
|
98
|
+
ncco[0].merge!(endOnExit: builder.endOnExit) if (builder.endOnExit || builder.endOnExit == false)
|
99
|
+
ncco[0].merge!(record: builder.record) if builder.record
|
100
|
+
ncco[0].merge!(canSpeak: builder.canSpeak) if builder.canSpeak
|
101
|
+
ncco[0].merge!(canHear: builder.canHear) if builder.canHear
|
102
|
+
ncco[0].merge!(mute: builder.mute) if builder.mute
|
103
|
+
|
104
|
+
ncco
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Voice::Actions::Input
|
6
|
+
attr_accessor :type, :dtmf, :speech, :eventUrl, :eventMethod
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
@type = attributes.fetch(:type)
|
10
|
+
@dtmf = attributes.fetch(:dtmf, nil)
|
11
|
+
@speech = attributes.fetch(:speech, nil)
|
12
|
+
@eventUrl = attributes.fetch(:eventUrl, nil)
|
13
|
+
@eventMethod = attributes.fetch(:eventMethod, nil)
|
14
|
+
|
15
|
+
after_initialize!
|
16
|
+
end
|
17
|
+
|
18
|
+
def after_initialize!
|
19
|
+
validate_type
|
20
|
+
|
21
|
+
if self.dtmf
|
22
|
+
validate_dtmf
|
23
|
+
end
|
24
|
+
|
25
|
+
if self.speech
|
26
|
+
validate_speech
|
27
|
+
end
|
28
|
+
|
29
|
+
if self.eventUrl
|
30
|
+
validate_event_url
|
31
|
+
end
|
32
|
+
|
33
|
+
if self.eventMethod
|
34
|
+
validate_event_method
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_type
|
39
|
+
valid_types = ['dtmf', 'speech']
|
40
|
+
|
41
|
+
raise ClientError.new("Invalid 'type', must be an Array of at least one String") unless self.type.is_a?(Array)
|
42
|
+
raise ClientError.new("Invalid 'type' value, must be 'dtmf', 'speech' or both 'dtmf' and 'speech'") if (valid_types & self.type).empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_dtmf
|
46
|
+
raise ClientError.new("Expected 'dtmf' to be included in 'type' parameter if 'dtmf' options specified") unless self.type.include?('dtmf')
|
47
|
+
|
48
|
+
if self.dtmf[:timeOut]
|
49
|
+
raise ClientError.new("Expected 'timeOut' to not be more than 10 seconds") if self.dtmf[:timeOut] > 10
|
50
|
+
end
|
51
|
+
|
52
|
+
if self.dtmf[:maxDigits]
|
53
|
+
raise ClientError.new("Expected 'maxDigits' to not be more than 22") if self.dtmf[:maxDigits] > 22
|
54
|
+
end
|
55
|
+
|
56
|
+
if self.dtmf[:submitOnHash]
|
57
|
+
raise ClientError.new("Invalid 'submitOnHash' value, must be a Boolean") unless self.dtmf[:submitOnHash] == true || self.dtmf[:submitOnHash] == false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_speech
|
62
|
+
raise ClientError.new("Expected 'speech' to be included in 'type' parameter if 'speech' options specified") unless self.type.include?('speech')
|
63
|
+
|
64
|
+
if self.speech[:uuid]
|
65
|
+
raise ClientError.new("Invalid 'uuid' value, must be an Array containing a single call leg ID element") unless self.speech[:uuid].is_a?(Array)
|
66
|
+
end
|
67
|
+
|
68
|
+
if self.speech[:endOnSilence]
|
69
|
+
raise ClientError.new("Expected 'endOnSilence' to not be more than 10 seconds") unless self.speech[:endOnSilence] <= 10 && self.speech[:endOnSilence] >= 0
|
70
|
+
end
|
71
|
+
|
72
|
+
if self.speech[:context]
|
73
|
+
raise ClientError.new("Expected 'context' to be an Array of strings") unless self.speech[:context].is_a?(Array)
|
74
|
+
end
|
75
|
+
|
76
|
+
if self.speech[:startTimeout]
|
77
|
+
raise ClientError.new("Expected 'startTimeout' to not be more than 10 seconds") unless self.speech[:startTimeout] <= 10 && self.speech[:startTimeout] >= 0
|
78
|
+
end
|
79
|
+
|
80
|
+
if self.speech[:maxDuration]
|
81
|
+
raise ClientError.new("Expected 'maxDuration' to not be more than 60 seconds") unless self.speech[:maxDuration] <= 60 && self.speech[:maxDuration] >= 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def validate_event_url
|
86
|
+
uri = URI.parse(self.eventUrl)
|
87
|
+
|
88
|
+
raise ClientError.new("Invalid 'eventUrl' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
89
|
+
|
90
|
+
self.eventUrl
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_event_method
|
94
|
+
valid_methods = ['GET', 'POST']
|
95
|
+
|
96
|
+
raise ClientError.new("Invalid 'eventMethod' value. must be either: 'GET' or 'POST'") unless valid_methods.include?(self.eventMethod.upcase)
|
97
|
+
end
|
98
|
+
|
99
|
+
def action
|
100
|
+
create_input!(self)
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_input!(builder)
|
104
|
+
ncco = [
|
105
|
+
{
|
106
|
+
action: 'input',
|
107
|
+
type: builder.type
|
108
|
+
}
|
109
|
+
]
|
110
|
+
|
111
|
+
ncco[0].merge!(dtmf: builder.dtmf) if builder.dtmf
|
112
|
+
ncco[0].merge!(speech: builder.speech) if builder.speech
|
113
|
+
ncco[0].merge!(eventUrl: builder.eventUrl) if builder.eventUrl
|
114
|
+
ncco[0].merge!(eventMethod: builder.eventMethod) if builder.eventMethod
|
115
|
+
|
116
|
+
ncco
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Voice::Actions::Notify
|
6
|
+
attr_accessor :payload, :eventUrl, :eventMethod
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
@payload = attributes.fetch(:payload)
|
10
|
+
@eventUrl = attributes.fetch(:eventUrl)
|
11
|
+
@eventMethod = attributes.fetch(:eventMethod, nil)
|
12
|
+
|
13
|
+
after_initialize!
|
14
|
+
end
|
15
|
+
|
16
|
+
def after_initialize!
|
17
|
+
validate_event_url
|
18
|
+
|
19
|
+
if self.eventMethod
|
20
|
+
validate_event_method
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_event_url
|
25
|
+
uri = URI.parse(self.eventUrl[0])
|
26
|
+
|
27
|
+
raise ClientError.new("Expected 'eventUrl' value to be an Array with a single string") unless self.eventUrl.is_a?(Array)
|
28
|
+
raise ClientError.new("Invalid 'eventUrl' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
29
|
+
|
30
|
+
self.eventUrl
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_event_method
|
34
|
+
valid_methods = ['GET', 'POST']
|
35
|
+
|
36
|
+
raise ClientError.new("Invalid 'eventMethod' value. must be either: 'GET' or 'POST'") unless valid_methods.include?(self.eventMethod.upcase)
|
37
|
+
end
|
38
|
+
|
39
|
+
def action
|
40
|
+
create_notify!(self)
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_notify!(builder)
|
44
|
+
ncco = [
|
45
|
+
{
|
46
|
+
action: 'notify',
|
47
|
+
payload: builder.payload,
|
48
|
+
eventUrl: builder.eventUrl
|
49
|
+
}
|
50
|
+
]
|
51
|
+
|
52
|
+
ncco[0].merge!(eventMethod: builder.eventMethod) if builder.eventMethod
|
53
|
+
|
54
|
+
ncco
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Voice::Actions::Record
|
6
|
+
attr_accessor :format, :split, :channels, :endOnSilence, :endOnKey, :timeOut, :beepStart, :eventUrl, :eventMethod
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
@format = attributes.fetch(:format, nil)
|
10
|
+
@split = attributes.fetch(:split, nil)
|
11
|
+
@channels = attributes.fetch(:channels, nil)
|
12
|
+
@endOnSilence = attributes.fetch(:endOnSilence, nil)
|
13
|
+
@endOnKey = attributes.fetch(:endOnKey, nil)
|
14
|
+
@timeOut = attributes.fetch(:timeOut, nil)
|
15
|
+
@beepStart = attributes.fetch(:beepStart, nil)
|
16
|
+
@eventUrl = attributes.fetch(:eventUrl, nil)
|
17
|
+
@eventMethod = attributes.fetch(:eventMethod, nil)
|
18
|
+
|
19
|
+
after_initialize!
|
20
|
+
end
|
21
|
+
|
22
|
+
def after_initialize!
|
23
|
+
if self.format
|
24
|
+
validate_format
|
25
|
+
end
|
26
|
+
|
27
|
+
if self.split
|
28
|
+
validate_split
|
29
|
+
end
|
30
|
+
|
31
|
+
if self.channels
|
32
|
+
validate_channels
|
33
|
+
end
|
34
|
+
|
35
|
+
if self.endOnSilence
|
36
|
+
validate_end_on_silence
|
37
|
+
end
|
38
|
+
|
39
|
+
if self.endOnKey
|
40
|
+
validate_end_on_key
|
41
|
+
end
|
42
|
+
|
43
|
+
if self.timeOut
|
44
|
+
validate_time_out
|
45
|
+
end
|
46
|
+
|
47
|
+
if self.beepStart
|
48
|
+
validate_beep_start
|
49
|
+
end
|
50
|
+
|
51
|
+
if self.eventUrl
|
52
|
+
validate_event_url
|
53
|
+
end
|
54
|
+
|
55
|
+
if self.eventMethod
|
56
|
+
validate_event_method
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def validate_format
|
61
|
+
valid_formats = ['mp3', 'wav', 'ogg']
|
62
|
+
|
63
|
+
raise ClientError.new("Invalid format, must be one of: 'mp3', 'wav', 'ogg'") unless valid_formats.include?(self.format)
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_split
|
67
|
+
raise ClientError.new("Expected 'split' value to be 'conversation' if defined") unless self.split == 'conversation'
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_channels
|
71
|
+
raise ClientError.new("The 'split' parameter must be defined to 'conversation' to also define 'channels'") unless self.split
|
72
|
+
|
73
|
+
raise ClientError.new("Expected 'split' parameter to be equal to or less than 32") unless self.channels <= 32
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_end_on_silence
|
77
|
+
raise ClientError.new("Expected 'endOnSilence' value to be between 3 and 10") unless self.endOnSilence <= 10 && self.endOnSilence >= 3
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_end_on_key
|
81
|
+
raise ClientError.new("Expected 'endOnKey' value to be a one of the following: a single digit between 1-9, '*' or '#'") unless self.endOnKey.match(/^(\*|[1-9]|\#)$/)
|
82
|
+
end
|
83
|
+
|
84
|
+
def validate_time_out
|
85
|
+
raise ClientError.new("Expected 'timeOut' value to be between 3 and 7200 seconds") unless self.timeOut <= 7200 && self.timeOut >= 3
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_beep_start
|
89
|
+
raise ClientError.new("Expected 'beepStart' value to be a Boolean") unless self.beepStart == true || self.beepStart == false
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate_event_url
|
93
|
+
uri = URI.parse(self.eventUrl)
|
94
|
+
|
95
|
+
raise ClientError.new("Invalid 'eventUrl' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
96
|
+
|
97
|
+
self.eventUrl
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_event_method
|
101
|
+
valid_methods = ['GET', 'POST']
|
102
|
+
|
103
|
+
raise ClientError.new("Invalid 'eventMethod' value. must be either: 'GET' or 'POST'") unless valid_methods.include?(self.eventMethod.upcase)
|
104
|
+
end
|
105
|
+
|
106
|
+
def action
|
107
|
+
create_record!(self)
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_record!(builder)
|
111
|
+
ncco = [
|
112
|
+
{
|
113
|
+
action: 'record'
|
114
|
+
}
|
115
|
+
]
|
116
|
+
|
117
|
+
ncco[0].merge!(format: builder.format) if builder.format
|
118
|
+
ncco[0].merge!(split: builder.split) if builder.split
|
119
|
+
ncco[0].merge!(channels: builder.channels) if builder.channels
|
120
|
+
ncco[0].merge!(endOnSilence: builder.endOnSilence) if builder.endOnSilence
|
121
|
+
ncco[0].merge!(endOnKey: builder.endOnKey) if builder.endOnKey
|
122
|
+
ncco[0].merge!(timeOut: builder.timeOut) if builder.timeOut
|
123
|
+
ncco[0].merge!(beepStart: builder.beepStart) if builder.beepStart
|
124
|
+
ncco[0].merge!(eventUrl: builder.eventUrl) if builder.eventUrl
|
125
|
+
ncco[0].merge!(eventMethod: builder.eventMethod) if builder.eventMethod
|
126
|
+
|
127
|
+
ncco
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Voice::Actions::Stream
|
6
|
+
attr_accessor :streamUrl, :level, :bargeIn, :loop
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
@streamUrl = attributes.fetch(:streamUrl)
|
10
|
+
@level = attributes.fetch(:level, nil)
|
11
|
+
@bargeIn = attributes.fetch(:bargeIn, nil)
|
12
|
+
@loop = attributes.fetch(:loop, nil)
|
13
|
+
|
14
|
+
after_initialize!
|
15
|
+
end
|
16
|
+
|
17
|
+
def after_initialize!
|
18
|
+
verify_stream_url
|
19
|
+
|
20
|
+
if self.level
|
21
|
+
verify_level
|
22
|
+
end
|
23
|
+
|
24
|
+
if self.bargeIn
|
25
|
+
verify_barge_in
|
26
|
+
end
|
27
|
+
|
28
|
+
if self.loop
|
29
|
+
verify_loop
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def verify_stream_url
|
34
|
+
raise ClientError.new("Expected 'streamUrl' parameter to be an Array containing a single string item") unless self.streamUrl.is_a?(Array)
|
35
|
+
|
36
|
+
uri = URI.parse(self.streamUrl[0])
|
37
|
+
|
38
|
+
raise ClientError.new("Invalid 'streamUrl' value, must be a valid URL") unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
|
39
|
+
end
|
40
|
+
|
41
|
+
def verify_level
|
42
|
+
raise ClientError.new("Expected 'level' value to be a number between -1 and 1") unless self.level.between?(-1, 1)
|
43
|
+
end
|
44
|
+
|
45
|
+
def verify_barge_in
|
46
|
+
raise ClientError.new("Expected 'bargeIn' value to be a Boolean") unless self.bargeIn == true || self.bargeIn == false
|
47
|
+
end
|
48
|
+
|
49
|
+
def verify_loop
|
50
|
+
raise ClientError.new("Expected 'loop' value to be either 1 or 0") unless self.loop == 1 || self.loop == 0
|
51
|
+
end
|
52
|
+
|
53
|
+
def action
|
54
|
+
create_stream!(self)
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_stream!(builder)
|
58
|
+
ncco = [
|
59
|
+
{
|
60
|
+
action: 'stream',
|
61
|
+
streamUrl: builder.streamUrl
|
62
|
+
}
|
63
|
+
]
|
64
|
+
|
65
|
+
ncco[0].merge!(level: builder.level) if builder.level
|
66
|
+
ncco[0].merge!(bargeIn: builder.bargeIn) if (builder.bargeIn || builder.bargeIn == false)
|
67
|
+
ncco[0].merge!(loop: builder.loop) if builder.loop
|
68
|
+
|
69
|
+
ncco
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|