vonage 7.2.1 → 7.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|