punchblock 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # develop
2
2
 
3
+ # v0.9.2 - 2012-02-18
4
+ * Feature: Asterisk calls receiving media commands are implicitly answered
5
+ * Bugfix: Unrenderable output documents on Asterisk should return a sensible error
6
+ * Bugfix: Log the target of commands correctly
7
+ * Bugfix: Do not wrap exceptions in ProtocolError
8
+
3
9
  # v0.9.1 - 2012-01-30
4
10
  * Bugfix: Closing an disconnected XMPP connection is a no-op
5
11
 
@@ -61,7 +61,7 @@ module Punchblock
61
61
  command.mixer_name ||= options[:mixer_name]
62
62
  command.component_id ||= options[:component_id]
63
63
  create_iq(jid_for_command(command)).tap do |iq|
64
- pb_logger.debug "Sending IQ ID #{iq.id} #{command.inspect} to #{jid}"
64
+ pb_logger.debug "Sending IQ ID #{iq.id} #{command.inspect} to #{iq.to}"
65
65
  iq << command
66
66
  end
67
67
  end
@@ -78,11 +78,6 @@ module Punchblock
78
78
  EM.run { client.run }
79
79
  rescue Blather::Stream::ConnectionFailed, Blather::Stream::ConnectionTimeout => e
80
80
  raise DisconnectedError.new(e.class.to_s, e.message)
81
- rescue => e
82
- # Preserve Punchblock native exceptions
83
- raise e if e.class.to_s =~ /^Punchblock/
84
- # Wrap everything else
85
- raise ProtocolError.new(e.class.to_s, e.message)
86
81
  end
87
82
  end
88
83
 
@@ -22,6 +22,7 @@ module Punchblock
22
22
  @channel, @translator = channel, translator
23
23
  @agi_env = parse_environment agi_env
24
24
  @id, @components = UUIDTools::UUID.random_create.to_s, {}
25
+ @answered = false
25
26
  pb_logger.debug "Starting up call with channel #{channel}, id #{@id}"
26
27
  end
27
28
 
@@ -73,6 +74,15 @@ module Punchblock
73
74
  direction == :inbound
74
75
  end
75
76
 
77
+ def answered?
78
+ @answered
79
+ end
80
+
81
+ def answer_if_not_answered
82
+ return if answered? || outbound?
83
+ execute_command Command::Answer.new
84
+ end
85
+
76
86
  def channel=(other)
77
87
  pb_logger.info "Channel is changing from #{channel} to #{other}."
78
88
  @channel = other
@@ -98,6 +108,7 @@ module Punchblock
98
108
  when '5'
99
109
  send_pb_event Event::Ringing.new
100
110
  when '6'
111
+ @answered = true
101
112
  send_pb_event Event::Answered.new
102
113
  end
103
114
  end
@@ -12,6 +12,7 @@ module Punchblock
12
12
  end
13
13
 
14
14
  def execute
15
+ @call.answer_if_not_answered
15
16
  initial_timeout = @component_node.initial_timeout || -1
16
17
  @inter_digit_timeout = @component_node.inter_digit_timeout || -1
17
18
 
@@ -11,6 +11,8 @@ module Punchblock
11
11
  end
12
12
 
13
13
  def execute
14
+ @call.answer_if_not_answered
15
+
14
16
  return with_error 'option error', 'An SSML document is required.' unless @component_node.ssml
15
17
 
16
18
  return with_error 'option error', 'An interrupt-on value of speech is unsupported.' if @component_node.interrupt_on == :speech
@@ -27,6 +29,8 @@ module Punchblock
27
29
  case node
28
30
  when RubySpeech::SSML::Audio
29
31
  lambda { current_actor.play_audio! node.src }
32
+ else
33
+ return with_error 'unrenderable document error', 'The provided document could not be rendered.'
30
34
  end
31
35
  end.compact
32
36
 
@@ -1,3 +1,3 @@
1
1
  module Punchblock
2
- VERSION = "0.9.1"
2
+ VERSION = "0.9.2"
3
3
  end
@@ -99,6 +99,49 @@ module Punchblock
99
99
  end
100
100
  end
101
101
 
102
+ describe '#answer_if_not_answered' do
103
+ let(:answer_command) { Command::Answer.new }
104
+
105
+ context "with a call that is already answered" do
106
+ it 'should not answer the call' do
107
+ subject.wrapped_object.expects(:'answered?').returns true
108
+ subject.wrapped_object.expects(:execute_command).never
109
+ subject.answer_if_not_answered
110
+ end
111
+ end
112
+
113
+ context "with an unanswered call" do
114
+ before do
115
+ subject.wrapped_object.expects(:'answered?').returns false
116
+ end
117
+
118
+ context "with a call that is outbound" do
119
+ let(:dial_command) { Command::Dial.new }
120
+
121
+ before do
122
+ dial_command.request!
123
+ subject.dial dial_command
124
+ end
125
+
126
+ it 'should not answer the call' do
127
+ subject.wrapped_object.expects(:execute_command).never
128
+ subject.answer_if_not_answered
129
+ end
130
+ end
131
+
132
+ context "with a call that is inbound" do
133
+ before do
134
+ subject.send_offer
135
+ end
136
+
137
+ it 'should answer a call that is inbound and not answered' do
138
+ subject.wrapped_object.expects(:execute_command).with(answer_command)
139
+ subject.answer_if_not_answered
140
+ end
141
+ end
142
+ end
143
+ end
144
+
102
145
  describe '#dial' do
103
146
  let(:dial_command_options) { {} }
104
147
 
@@ -354,6 +397,11 @@ module Punchblock
354
397
  translator.expects(:handle_pb_event!).with expected_ringing
355
398
  subject.process_ami_event ami_event
356
399
  end
400
+
401
+ it '#answered? should return false' do
402
+ subject.process_ami_event ami_event
403
+ subject.answered?.should be_false
404
+ end
357
405
  end
358
406
 
359
407
  context 'up' do
@@ -366,6 +414,11 @@ module Punchblock
366
414
  translator.expects(:handle_pb_event!).with expected_answered
367
415
  subject.process_ami_event ami_event
368
416
  end
417
+
418
+ it '#answered? should be true' do
419
+ subject.process_ami_event ami_event
420
+ subject.answered?.should be_true
421
+ end
369
422
  end
370
423
  end
371
424
 
@@ -40,6 +40,13 @@ module Punchblock
40
40
  describe '#execute' do
41
41
  before { command.request! }
42
42
 
43
+ it "calls answer_if_not_answered on the call" do
44
+ call.expects :answer_if_not_answered
45
+ subject.execute
46
+ end
47
+
48
+ before { call.stubs :answer_if_not_answered }
49
+
43
50
  context 'with a media engine of :unimrcp' do
44
51
  pending
45
52
  let(:media_engine) { :unimrcp }
@@ -33,6 +33,13 @@ module Punchblock
33
33
  describe '#execute' do
34
34
  before { command.request! }
35
35
 
36
+ it "calls answer_if_not_answered on the call" do
37
+ mock_call.expects :answer_if_not_answered
38
+ subject.execute
39
+ end
40
+
41
+ before { mock_call.stubs :answer_if_not_answered }
42
+
36
43
  context 'with a media engine of :unimrcp' do
37
44
  let(:media_engine) { :unimrcp }
38
45
 
@@ -247,7 +254,6 @@ module Punchblock
247
254
  let :ssml_doc do
248
255
  RubySpeech::SSML.draw do
249
256
  audio :src => audio_filename
250
- say_as(:interpret_as => :cardinal) { 'FOO' }
251
257
  end
252
258
  end
253
259
 
@@ -332,6 +338,22 @@ module Punchblock
332
338
  subject.execute
333
339
  end
334
340
  end
341
+
342
+ context "with an SSML document containing elements other than <audio/>" do
343
+ let :command_options do
344
+ {
345
+ :ssml => RubySpeech::SSML.draw do
346
+ string "FooBar"
347
+ end
348
+ }
349
+ end
350
+
351
+ it "should return an unrenderable document error" do
352
+ subject.execute
353
+ error = ProtocolError.new 'unrenderable document error', 'The provided document could not be rendered.'
354
+ command.response(0.1).should == error
355
+ end
356
+ end
335
357
  end
336
358
 
337
359
  describe 'start-offset' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: punchblock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,11 +11,11 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-01-30 00:00:00.000000000 Z
14
+ date: 2012-02-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: niceogiri
18
- requirement: &2156532180 !ruby/object:Gem::Requirement
18
+ requirement: &2160948720 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ! '>='
@@ -23,10 +23,10 @@ dependencies:
23
23
  version: 0.0.4
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *2156532180
26
+ version_requirements: *2160948720
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: blather
29
- requirement: &2156531500 !ruby/object:Gem::Requirement
29
+ requirement: &2160948120 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ! '>='
@@ -34,10 +34,10 @@ dependencies:
34
34
  version: 0.5.12
35
35
  type: :runtime
36
36
  prerelease: false
37
- version_requirements: *2156531500
37
+ version_requirements: *2160948120
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: activesupport
40
- requirement: &2156530720 !ruby/object:Gem::Requirement
40
+ requirement: &2160942420 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ! '>='
@@ -45,10 +45,10 @@ dependencies:
45
45
  version: 2.1.0
46
46
  type: :runtime
47
47
  prerelease: false
48
- version_requirements: *2156530720
48
+ version_requirements: *2160942420
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: state_machine
51
- requirement: &2156527320 !ruby/object:Gem::Requirement
51
+ requirement: &2160941560 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
54
  - - ! '>='
@@ -56,10 +56,10 @@ dependencies:
56
56
  version: 1.0.1
57
57
  type: :runtime
58
58
  prerelease: false
59
- version_requirements: *2156527320
59
+ version_requirements: *2160941560
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: future-resource
62
- requirement: &2156526620 !ruby/object:Gem::Requirement
62
+ requirement: &2160940660 !ruby/object:Gem::Requirement
63
63
  none: false
64
64
  requirements:
65
65
  - - ! '>='
@@ -67,10 +67,10 @@ dependencies:
67
67
  version: 0.0.2
68
68
  type: :runtime
69
69
  prerelease: false
70
- version_requirements: *2156526620
70
+ version_requirements: *2160940660
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: has-guarded-handlers
73
- requirement: &2156525820 !ruby/object:Gem::Requirement
73
+ requirement: &2160939900 !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
76
76
  - - ! '>='
@@ -78,10 +78,10 @@ dependencies:
78
78
  version: 0.1.0
79
79
  type: :runtime
80
80
  prerelease: false
81
- version_requirements: *2156525820
81
+ version_requirements: *2160939900
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: celluloid
84
- requirement: &2156525140 !ruby/object:Gem::Requirement
84
+ requirement: &2160939080 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
87
  - - ! '>='
@@ -89,10 +89,10 @@ dependencies:
89
89
  version: 0.6.0
90
90
  type: :runtime
91
91
  prerelease: false
92
- version_requirements: *2156525140
92
+ version_requirements: *2160939080
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: ruby_ami
95
- requirement: &2156524300 !ruby/object:Gem::Requirement
95
+ requirement: &2160938500 !ruby/object:Gem::Requirement
96
96
  none: false
97
97
  requirements:
98
98
  - - ! '>='
@@ -100,10 +100,10 @@ dependencies:
100
100
  version: 0.1.3
101
101
  type: :runtime
102
102
  prerelease: false
103
- version_requirements: *2156524300
103
+ version_requirements: *2160938500
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: ruby_speech
106
- requirement: &2156523400 !ruby/object:Gem::Requirement
106
+ requirement: &2160937920 !ruby/object:Gem::Requirement
107
107
  none: false
108
108
  requirements:
109
109
  - - ! '>='
@@ -111,10 +111,10 @@ dependencies:
111
111
  version: 0.5.1
112
112
  type: :runtime
113
113
  prerelease: false
114
- version_requirements: *2156523400
114
+ version_requirements: *2160937920
115
115
  - !ruby/object:Gem::Dependency
116
116
  name: bundler
117
- requirement: &2156522860 !ruby/object:Gem::Requirement
117
+ requirement: &2160937220 !ruby/object:Gem::Requirement
118
118
  none: false
119
119
  requirements:
120
120
  - - ~>
@@ -122,10 +122,10 @@ dependencies:
122
122
  version: 1.0.0
123
123
  type: :development
124
124
  prerelease: false
125
- version_requirements: *2156522860
125
+ version_requirements: *2160937220
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: rspec
128
- requirement: &2156522160 !ruby/object:Gem::Requirement
128
+ requirement: &2160936620 !ruby/object:Gem::Requirement
129
129
  none: false
130
130
  requirements:
131
131
  - - ~>
@@ -133,10 +133,10 @@ dependencies:
133
133
  version: 2.7.0
134
134
  type: :development
135
135
  prerelease: false
136
- version_requirements: *2156522160
136
+ version_requirements: *2160936620
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: ci_reporter
139
- requirement: &2156521620 !ruby/object:Gem::Requirement
139
+ requirement: &2160935800 !ruby/object:Gem::Requirement
140
140
  none: false
141
141
  requirements:
142
142
  - - ! '>='
@@ -144,10 +144,10 @@ dependencies:
144
144
  version: 1.6.3
145
145
  type: :development
146
146
  prerelease: false
147
- version_requirements: *2156521620
147
+ version_requirements: *2160935800
148
148
  - !ruby/object:Gem::Dependency
149
149
  name: yard
150
- requirement: &2156520980 !ruby/object:Gem::Requirement
150
+ requirement: &2160935180 !ruby/object:Gem::Requirement
151
151
  none: false
152
152
  requirements:
153
153
  - - ~>
@@ -155,10 +155,10 @@ dependencies:
155
155
  version: 0.6.0
156
156
  type: :development
157
157
  prerelease: false
158
- version_requirements: *2156520980
158
+ version_requirements: *2160935180
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rake
161
- requirement: &2156520420 !ruby/object:Gem::Requirement
161
+ requirement: &2160934640 !ruby/object:Gem::Requirement
162
162
  none: false
163
163
  requirements:
164
164
  - - ! '>='
@@ -166,10 +166,10 @@ dependencies:
166
166
  version: '0'
167
167
  type: :development
168
168
  prerelease: false
169
- version_requirements: *2156520420
169
+ version_requirements: *2160934640
170
170
  - !ruby/object:Gem::Dependency
171
171
  name: mocha
172
- requirement: &2156519840 !ruby/object:Gem::Requirement
172
+ requirement: &2160934140 !ruby/object:Gem::Requirement
173
173
  none: false
174
174
  requirements:
175
175
  - - ! '>='
@@ -177,10 +177,10 @@ dependencies:
177
177
  version: '0'
178
178
  type: :development
179
179
  prerelease: false
180
- version_requirements: *2156519840
180
+ version_requirements: *2160934140
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: i18n
183
- requirement: &2156516740 !ruby/object:Gem::Requirement
183
+ requirement: &2160933560 !ruby/object:Gem::Requirement
184
184
  none: false
185
185
  requirements:
186
186
  - - ! '>='
@@ -188,10 +188,10 @@ dependencies:
188
188
  version: '0'
189
189
  type: :development
190
190
  prerelease: false
191
- version_requirements: *2156516740
191
+ version_requirements: *2160933560
192
192
  - !ruby/object:Gem::Dependency
193
193
  name: countdownlatch
194
- requirement: &2156515500 !ruby/object:Gem::Requirement
194
+ requirement: &2160933040 !ruby/object:Gem::Requirement
195
195
  none: false
196
196
  requirements:
197
197
  - - ! '>='
@@ -199,10 +199,10 @@ dependencies:
199
199
  version: '0'
200
200
  type: :development
201
201
  prerelease: false
202
- version_requirements: *2156515500
202
+ version_requirements: *2160933040
203
203
  - !ruby/object:Gem::Dependency
204
204
  name: guard-rspec
205
- requirement: &2156514720 !ruby/object:Gem::Requirement
205
+ requirement: &2160932600 !ruby/object:Gem::Requirement
206
206
  none: false
207
207
  requirements:
208
208
  - - ! '>='
@@ -210,7 +210,7 @@ dependencies:
210
210
  version: '0'
211
211
  type: :development
212
212
  prerelease: false
213
- version_requirements: *2156514720
213
+ version_requirements: *2160932600
214
214
  description: Like Rack is to Rails and Sinatra, Punchblock provides a consistent API
215
215
  on top of several underlying third-party call control protocols.
216
216
  email: punchblock@adhearsion.com
@@ -351,7 +351,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
351
351
  version: '0'
352
352
  segments:
353
353
  - 0
354
- hash: 4401159301210104639
354
+ hash: 326151845753571314
355
355
  required_rubygems_version: !ruby/object:Gem::Requirement
356
356
  none: false
357
357
  requirements: