adhearsion 2.5.4 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/CHANGELOG.md +15 -0
  4. data/README.markdown +2 -1
  5. data/Rakefile +1 -6
  6. data/adhearsion.gemspec +4 -3
  7. data/features/cli_daemon.feature +2 -4
  8. data/features/cli_restart.feature +14 -5
  9. data/features/cli_start.feature +0 -2
  10. data/features/cli_stop.feature +15 -6
  11. data/lib/adhearsion.rb +21 -23
  12. data/lib/adhearsion/call.rb +49 -5
  13. data/lib/adhearsion/call_controller.rb +29 -11
  14. data/lib/adhearsion/call_controller/dial.rb +21 -9
  15. data/lib/adhearsion/call_controller/menu_dsl.rb +12 -12
  16. data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +1 -1
  17. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +1 -0
  18. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +1 -1
  19. data/lib/adhearsion/call_controller/output.rb +36 -7
  20. data/lib/adhearsion/call_controller/output/abstract_player.rb +4 -0
  21. data/lib/adhearsion/call_controller/record.rb +1 -0
  22. data/lib/adhearsion/cli_commands/ahn_command.rb +7 -4
  23. data/lib/adhearsion/cli_commands/plugin_command.rb +2 -0
  24. data/lib/adhearsion/generators.rb +2 -4
  25. data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +20 -20
  26. data/lib/adhearsion/initializer.rb +2 -2
  27. data/lib/adhearsion/plugin.rb +6 -6
  28. data/lib/adhearsion/punchblock_plugin.rb +3 -4
  29. data/lib/adhearsion/punchblock_plugin/initializer.rb +2 -1
  30. data/lib/adhearsion/router.rb +7 -7
  31. data/lib/adhearsion/router/route.rb +10 -4
  32. data/lib/adhearsion/rspec.rb +2 -0
  33. data/lib/adhearsion/version.rb +1 -1
  34. data/spec/adhearsion/call_controller/dial_spec.rb +589 -557
  35. data/spec/adhearsion/call_controller/input_spec.rb +91 -91
  36. data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +29 -29
  37. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +6 -6
  38. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +19 -19
  39. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +6 -6
  40. data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +1 -1
  41. data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +21 -17
  42. data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +96 -83
  43. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +5 -5
  44. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +9 -9
  45. data/spec/adhearsion/call_controller/output/async_player_spec.rb +14 -4
  46. data/spec/adhearsion/call_controller/output/formatter_spec.rb +14 -14
  47. data/spec/adhearsion/call_controller/output/player_spec.rb +15 -5
  48. data/spec/adhearsion/call_controller/output_spec.rb +126 -78
  49. data/spec/adhearsion/call_controller/record_spec.rb +38 -26
  50. data/spec/adhearsion/call_controller/utility_spec.rb +11 -11
  51. data/spec/adhearsion/call_controller_spec.rb +176 -136
  52. data/spec/adhearsion/call_spec.rb +443 -218
  53. data/spec/adhearsion/calls_spec.rb +33 -33
  54. data/spec/adhearsion/configuration_spec.rb +61 -61
  55. data/spec/adhearsion/console_spec.rb +29 -29
  56. data/spec/adhearsion/events_spec.rb +14 -14
  57. data/spec/adhearsion/generators_spec.rb +1 -1
  58. data/spec/adhearsion/initializer_spec.rb +42 -42
  59. data/spec/adhearsion/logging_spec.rb +33 -33
  60. data/spec/adhearsion/outbound_call_spec.rb +69 -55
  61. data/spec/adhearsion/plugin_spec.rb +53 -44
  62. data/spec/adhearsion/process_spec.rb +21 -21
  63. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +68 -52
  64. data/spec/adhearsion/punchblock_plugin_spec.rb +6 -6
  65. data/spec/adhearsion/router/evented_route_spec.rb +2 -2
  66. data/spec/adhearsion/router/openended_route_spec.rb +9 -9
  67. data/spec/adhearsion/router/route_spec.rb +61 -31
  68. data/spec/adhearsion/router/unaccepting_route_spec.rb +13 -13
  69. data/spec/adhearsion/router_spec.rb +47 -33
  70. data/spec/adhearsion/statistics/dump_spec.rb +6 -6
  71. data/spec/adhearsion/statistics_spec.rb +9 -9
  72. data/spec/adhearsion_spec.rb +23 -20
  73. data/spec/spec_helper.rb +3 -6
  74. data/spec/support/call_controller_test_helpers.rb +7 -7
  75. data/spec/support/initializer_stubs.rb +1 -1
  76. data/spec/support/punchblock_mocks.rb +1 -1
  77. metadata +22 -10
  78. data/features/support/utils.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 934b35739888ae39b19f72ea09e02289ebc56bb5
4
- data.tar.gz: 8f84e7ccdc30266aff7fe3ff47854dff86511efb
3
+ metadata.gz: cdd9595f782bf66bc47865e7738e5da1c973d842
4
+ data.tar.gz: 916b8a0a4a2a07b0a7464f281c05d9a096043acf
5
5
  SHA512:
6
- metadata.gz: f23fb10c0bdaa93a47f4a4516d756d452a611d07282c8f1396b2c4132f08e7ff1be4af6cec65ebb40a0752d15e6509c04621fb1a13853e4da33f693eae15075d
7
- data.tar.gz: 5516860dc709922c9d7babe161d5f760a91a1ce20c9af8cdf68ee2ac3d737258a1acd62d896ffb76c45ffd6405c1a3f3c62d0277b93bbe5b69e494593904b149
6
+ metadata.gz: 0114fe9c93594187df01011c321e33f754cb6d438d68d6d6bf670b63d926f0cbdae3c59929974c177d37bc724e664e465f0baa0d9b77797f33291bb193a0c77f
7
+ data.tar.gz: cddca9472cccaa2e7a7a526d7bdd8a57f95ab2e5fa3bc171ef26463dcd4dbcacc289ab8947a7628e349f4e345295b79f6f4d1543ed56fbea1a59560e0664860f
data/.rspec CHANGED
@@ -1,3 +1,4 @@
1
1
  --format documentation
2
2
  --colour
3
3
  --tty
4
+ --profile
@@ -1,5 +1,20 @@
1
1
  # [develop](https://github.com/adhearsion/adhearsion)
2
2
 
3
+ # [2.6.0](https://github.com/adhearsion/adhearsion/compare/v2.5.4...v2.6.0) - [2015-02-01](https://rubygems.org/gems/adhearsion/versions/2.6.0)
4
+ * Feature: `Call#after_hangup_lifetime` optionally overrides `Adhearsion.config.platform.after_hangup_lifetime` ([#537](https://github.com/adhearsion/adhearsion/pull/537))
5
+ * Feature: Accept a `:cleanup` parameter in Dial options, which specifies a controller to be run on each outbound call before cleanup. ([#484](https://github.com/adhearsion/adhearsion/pull/484))
6
+ * Feature: Add a per-controller callback `on_error` that is invoked whenever an unhandled exception is raised. This can be used to play apology messages before disconnecting the caller ([#486](https://github.com/adhearsion/adhearsion/issues/486))
7
+ * Feature: Add `Call#redirect` and `CallController#redirect` for redirecting calls to other systems ([#465](https://github.com/adhearsion/adhearsion/issues/465))
8
+ * Feature: Ensure logging is available on STDOUT during RSpec runs ([#489](https://github.com/adhearsion/adhearsion/pull/489))
9
+ * Feature: Reduce Adhearsion start-up time by selectively requiring the parts of ActiveSupport we use
10
+ * Feature: `Call#unjoin` does not require a `target`, allowing to unjoin from all existing joins ([#519](https://github.com/adhearsion/adhearsion/pull/519))
11
+ * Feature: Add `Output#play_document` and `Output#play_document!` for playing an SSML document from a URL ([#535](https://github.com/adhearsion/adhearsion/pull/535))
12
+ * Bugfix: Logging around post-routing call termination now accounts for the call already being down.
13
+ * Bugfix: Bubble component complete events to other registered handlers
14
+ * Bugfix: Calling `ahn restart` on a stopped application now works
15
+ * Documentation: Improved INFO level log messages ([#518](https://github.com/adhearsion/adhearsion/pull/518))
16
+ * Update: Update Punchblock to fix Celluloid incompatibility ([#521](https://github.com/adhearsion/adhearsion/pull/521))
17
+
3
18
  # [2.5.4](https://github.com/adhearsion/adhearsion/compare/v2.5.3...v2.5.4) - [2014-07-18](https://rubygems.org/gems/adhearsion/versions/2.5.4)
4
19
  * Bugfix: Ignore dead calls when searching by tag
5
20
  * Bugfix: Routing a dead call should end cleanly ([#441](https://github.com/adhearsion/adhearsion/issues/441))
@@ -3,6 +3,7 @@
3
3
  [![Dependency Status](https://gemnasium.com/adhearsion/adhearsion.png?travis)](https://gemnasium.com/adhearsion/adhearsion)
4
4
  [![Code Climate](https://codeclimate.com/github/adhearsion/adhearsion.png)](https://codeclimate.com/github/adhearsion/adhearsion)
5
5
  [![Coverage Status](https://coveralls.io/repos/adhearsion/adhearsion/badge.png?branch=develop)](https://coveralls.io/r/adhearsion/adhearsion)
6
+ [![Inline docs](http://inch-ci.org/github/adhearsion/adhearsion.png?branch=develop)](http://inch-ci.org/github/adhearsion/adhearsion)
6
7
 
7
8
  # Adhearsion
8
9
 
@@ -82,4 +83,4 @@ There is a pre-commit hook that runs encoding checks available in pre-commit. To
82
83
 
83
84
  ### Copyright
84
85
 
85
- Copyright (c) 2011-2013 Adhearsion Foundation Inc. MIT LICENSE (see LICENSE for details).
86
+ Copyright (c) 2011-2014 Adhearsion Foundation Inc. MIT LICENSE (see LICENSE for details).
data/Rakefile CHANGED
@@ -11,15 +11,10 @@ RSpec::Core::RakeTask.new(:spec) do |t|
11
11
  # t.ruby_opts = "-w -r./spec/capture_warnings"
12
12
  end
13
13
 
14
- require 'ci/reporter/rake/rspec'
15
- require 'ci/reporter/rake/cucumber'
16
- task :ci => ['ci:setup:rspec', :spec, 'ci:setup:rspec', :features]
17
-
18
14
  require 'cucumber'
19
15
  require 'cucumber/rake/task'
20
- require 'ci/reporter/rake/cucumber'
21
16
  Cucumber::Rake::Task.new(:features) do |t|
22
- t.cucumber_opts = %w{--tags ~@jruby} unless defined?(JRUBY_VERSION)
17
+ t.cucumber_opts = %w{--tags ~@skip_jruby} if defined?(JRUBY_VERSION)
23
18
  end
24
19
 
25
20
  Cucumber::Rake::Task.new(:wip) do |t|
@@ -33,17 +33,18 @@ Gem::Specification.new do |s|
33
33
  s.add_runtime_dependency 'jruby-openssl' if RUBY_PLATFORM == 'java'
34
34
  s.add_runtime_dependency 'logging', ["~> 1.8"]
35
35
  s.add_runtime_dependency 'pry'
36
- s.add_runtime_dependency 'punchblock', ["~> 2.4"]
36
+ s.add_runtime_dependency 'punchblock', ["~> 2.6"]
37
37
  s.add_runtime_dependency 'rake'
38
38
  s.add_runtime_dependency 'ruby_speech', ["~> 2.0"]
39
39
  s.add_runtime_dependency 'thor', "~> 0.18.0"
40
40
 
41
41
  s.add_development_dependency 'aruba', "~> 0.5"
42
- s.add_development_dependency 'ci_reporter'
42
+ s.add_development_dependency 'ci_reporter_rspec'
43
+ s.add_development_dependency 'ci_reporter_cucumber'
43
44
  s.add_development_dependency 'cucumber'
44
45
  s.add_development_dependency 'guard-cucumber'
45
46
  s.add_development_dependency 'guard-rspec'
46
- s.add_development_dependency 'rspec', ["~> 2.13"]
47
+ s.add_development_dependency 'rspec', ["~> 3.0"]
47
48
  s.add_development_dependency 'simplecov'
48
49
  s.add_development_dependency 'simplecov-rcov'
49
50
  s.add_development_dependency 'yard'
@@ -3,18 +3,16 @@ Feature: Adhearsion Ahn CLI (daemon)
3
3
  I want the ahn command to provide a 'daemon' command
4
4
  So that I can start my adhearsion app as a daemon
5
5
 
6
- @reconnect
6
+ @reconnect @skip_jruby
7
7
  Scenario: Command daemon with path works correctly
8
- Given JRuby skip test
9
8
  Given that I create a valid app under "path/somewhere"
10
9
  When I run `ahn daemon path/somewhere`
11
10
  And I cd to "path/somewhere"
12
11
  And I terminate the process using the pid file "adhearsion.pid"
13
12
  Then the exit status should be 0
14
13
 
15
- @reconnect
14
+ @reconnect @skip_jruby
16
15
  Scenario: Command daemon with pid option
17
- Given JRuby skip test
18
16
  Given that I create a valid app under "path/somewhere"
19
17
  When I run `ahn daemon path/somewhere --pid-file=ahn.pid`
20
18
  And I cd to "path/somewhere"
@@ -3,9 +3,8 @@ Feature: Adhearsion Ahn CLI (restart)
3
3
  I want the ahn command to provide a 'restart' command
4
4
  So that I can restart a running Adhearsion daemon
5
5
 
6
- @reconnect
6
+ @reconnect @skip_jruby
7
7
  Scenario: Command restart with a missing or wrong pid
8
- Given JRuby skip test
9
8
  Given that I create a valid app under "path/somewhere"
10
9
  When I run `ahn daemon path/somewhere --pid-file=ahn.pid`
11
10
  And I run `ahn restart path/somewhere --pid-file=ahn2.pid`
@@ -29,9 +28,8 @@ Feature: Adhearsion Ahn CLI (restart)
29
28
  """
30
29
  And the exit status should be 1
31
30
 
32
- @reconnect
31
+ @reconnect @skip_jruby
33
32
  Scenario: Command restart with no path inside of the app directory
34
- Given JRuby skip test
35
33
  Given that I create a valid app under "path/somewhere"
36
34
  When I cd to "path/somewhere"
37
35
  And I run `ahn daemon --pid-file=ahn.pid`
@@ -40,4 +38,15 @@ Feature: Adhearsion Ahn CLI (restart)
40
38
  """
41
39
  Starting Adhearsion
42
40
  """
43
- And the exit status should be 0
41
+ And the exit status should be 0
42
+
43
+ @reconnect @skip_jruby
44
+ Scenario: Command restart on a stopped application
45
+ Given that I create a valid app under "path/somewhere"
46
+ When I cd to "path/somewhere"
47
+ And I run `ahn restart --pid-file=ahn.pid`
48
+ Then the output should contain:
49
+ """
50
+ Starting Adhearsion
51
+ """
52
+ And the exit status should be 0
@@ -12,7 +12,6 @@ Feature: Adhearsion Ahn CLI (start)
12
12
  And the exit status should be 1
13
13
 
14
14
  Scenario: Command start with no path inside of the app directory
15
- Given JRuby skip test because the console causes the process to never exit
16
15
  And that I create a valid app under "path/somewhere"
17
16
  When I cd to "path/somewhere"
18
17
  And I run `ahn start` interactively
@@ -21,7 +20,6 @@ Feature: Adhearsion Ahn CLI (start)
21
20
  And the output should contain "Adhearsion shut down"
22
21
 
23
22
  Scenario: Command start with only path works properly
24
- Given JRuby skip test waiting for https://jira.codehaus.org/browse/JRUBY-6994
25
23
  And that I create a valid app under "path/somewhere"
26
24
  When I run `ahn start path/somewhere` interactively
27
25
  And I wait for output to contain "Starting connection to server"
@@ -3,9 +3,8 @@ Feature: Adhearsion Ahn CLI (stop)
3
3
  I want the ahn command to provide a 'stop' command
4
4
  So that I can stop a running Adhearsion daemon
5
5
 
6
- @reconnect
6
+ @reconnect @skip_jruby
7
7
  Scenario: Command stop with valid path and pid option
8
- Given JRuby skip test
9
8
  Given that I create a valid app under "path/somewhere"
10
9
  When I run `ahn daemon path/somewhere --pid-file=ahn.pid`
11
10
  And I run `ahn stop path/somewhere --pid-file=ahn.pid`
@@ -15,9 +14,8 @@ Feature: Adhearsion Ahn CLI (stop)
15
14
  """
16
15
  And the file "ahn.pid" should not exist
17
16
 
18
- @reconnect
17
+ @reconnect @skip_jruby
19
18
  Scenario: Command stop with valid path and no pid option
20
- Given JRuby skip test
21
19
  Given that I create a valid app under "path/somewhere"
22
20
  When I run `ahn daemon path/somewhere`
23
21
  And I run `ahn stop path/somewhere`
@@ -27,9 +25,8 @@ Feature: Adhearsion Ahn CLI (stop)
27
25
  """
28
26
  And the file "path/somewhere/adhearsion.pid" should not exist
29
27
 
30
- @reconnect
28
+ @reconnect @skip_jruby
31
29
  Scenario: Command stop with no options inside the app directory
32
- Given JRuby skip test
33
30
  Given that I create a valid app under "path/somewhere"
34
31
  And I cd to "path/somewhere"
35
32
  When I run `ahn daemon`
@@ -39,3 +36,15 @@ Feature: Adhearsion Ahn CLI (stop)
39
36
  Stopping Adhearsion
40
37
  """
41
38
  And the file "adhearsion.pid" should not exist
39
+
40
+ @reconnect @skip_jruby
41
+ Scenario: Command stop with pid option inside the app directory
42
+ Given that I create a valid app under "path/somewhere"
43
+ And I cd to "path/somewhere"
44
+ When I run `ahn daemon --pid-file=ahn.pid`
45
+ And I run `ahn stop --pid-file=ahn.pid`
46
+ Then the output should contain:
47
+ """
48
+ Stopping Adhearsion
49
+ """
50
+ And the file "ahn.pid" should not exist
@@ -2,36 +2,15 @@
2
2
 
3
3
  abort "ERROR: You are running Adhearsion on an unsupported version of Ruby (Ruby #{RUBY_VERSION} #{RUBY_RELEASE_DATE})! Please upgrade to at least Ruby v1.9.3, JRuby 1.7.0 or Rubinius 2.0." if RUBY_VERSION < "1.9.3"
4
4
 
5
- %w{
6
- active_support/all
5
+ %w(
7
6
  punchblock
8
7
  celluloid
8
+ ).each { |r| require r }
9
9
 
10
- adhearsion/version
11
- adhearsion/foundation
12
- }.each { |f| require f }
13
10
 
14
11
  module Adhearsion
15
- extend ActiveSupport::Autoload
16
-
17
12
  Error = Class.new StandardError
18
13
 
19
- autoload :Call
20
- autoload :CallController
21
- autoload :Calls
22
- autoload :Configuration
23
- autoload :Console
24
- autoload :Dispatcher
25
- autoload :Events
26
- autoload :Generators
27
- autoload :Initializer
28
- autoload :Logging
29
- autoload :OutboundCall
30
- autoload :Plugin
31
- autoload :Process
32
- autoload :Router
33
- autoload :Statistics
34
-
35
14
  class << self
36
15
 
37
16
  #
@@ -130,3 +109,22 @@ module Celluloid
130
109
  end
131
110
  end
132
111
  end
112
+
113
+ %w(
114
+ version
115
+ foundation
116
+ call
117
+ call_controller
118
+ calls
119
+ configuration
120
+ console
121
+ events
122
+ generators
123
+ initializer
124
+ logging
125
+ outbound_call
126
+ plugin
127
+ process
128
+ router
129
+ statistics
130
+ ).each { |f| require "adhearsion/#{f}" }
@@ -3,6 +3,8 @@
3
3
  require 'has_guarded_handlers'
4
4
  require 'thread'
5
5
  require 'active_support/hash_with_indifferent_access'
6
+ require 'active_support/core_ext/hash/indifferent_access'
7
+ require 'adhearsion'
6
8
 
7
9
  module Adhearsion
8
10
  ##
@@ -48,9 +50,12 @@ module Adhearsion
48
50
  # @return [Time] the time at which the call began. For inbound calls this is the time at which the call was offered to Adhearsion. For outbound calls it is the time at which the remote party answered.
49
51
  attr_reader :end_time
50
52
 
51
- # @return [true, false] wether or not the call should be automatically hung up after executing its controller
53
+ # @return [true, false] whether or not the call should be automatically hung up after executing its controller
52
54
  attr_accessor :auto_hangup
53
55
 
56
+ # @return [Integer] the number of seconds after the call is hung up that the controller will remain active
57
+ attr_accessor :after_hangup_lifetime
58
+
54
59
  delegate :[], :[]=, :to => :variables
55
60
 
56
61
  # @return [String] the value of the To header from the signaling protocol
@@ -82,6 +87,7 @@ module Adhearsion
82
87
  @peers = {}
83
88
  @duration = nil
84
89
  @auto_hangup = true
90
+ @after_hangup_lifetime = nil
85
91
 
86
92
  self << offer if offer
87
93
  end
@@ -230,7 +236,7 @@ module Adhearsion
230
236
  end
231
237
 
232
238
  on_end do |event|
233
- logger.info "Call ended due to #{event.reason}"
239
+ logger.info "Call #{from} -> #{to} ended due to #{event.reason}#{" (code #{event.platform_code})" if event.platform_code}"
234
240
  @end_time = event.timestamp.to_time
235
241
  @duration = @end_time - @start_time if @start_time
236
242
  clear_from_active_calls
@@ -238,7 +244,7 @@ module Adhearsion
238
244
  @end_code = event.platform_code
239
245
  @end_blocker.broadcast event.reason
240
246
  @commands.terminate
241
- after(Adhearsion.config.platform.after_hangup_lifetime) { terminate }
247
+ after(@after_hangup_lifetime || Adhearsion.config.platform.after_hangup_lifetime) { terminate }
242
248
  end
243
249
  end
244
250
 
@@ -295,15 +301,41 @@ module Adhearsion
295
301
 
296
302
  def accept(headers = nil)
297
303
  @accept_command ||= write_and_await_response Punchblock::Command::Accept.new(:headers => headers)
304
+ rescue Punchblock::ProtocolError => e
305
+ abort e
298
306
  end
299
307
 
300
308
  def answer(headers = nil)
301
309
  write_and_await_response Punchblock::Command::Answer.new(:headers => headers)
310
+ rescue Punchblock::ProtocolError => e
311
+ abort e
302
312
  end
303
313
 
304
314
  def reject(reason = :busy, headers = nil)
305
315
  write_and_await_response Punchblock::Command::Reject.new(:reason => reason, :headers => headers)
306
316
  Adhearsion::Events.trigger_immediately :call_rejected, call: current_actor, reason: reason
317
+ rescue Punchblock::ProtocolError => e
318
+ abort e
319
+ end
320
+
321
+ #
322
+ # Redirect the call to some other target system.
323
+ #
324
+ # If the redirect is successful, the call will be released from the
325
+ # telephony engine and Adhearsion will lose control of the call.
326
+ #
327
+ # Note that for the common case, this will result in a SIP 302 or
328
+ # SIP REFER, which provides the caller with a new URI to dial. As such,
329
+ # the redirect target cannot be any telephony-engine specific address
330
+ # (such as sofia/gateway, agent/101, or SIP/mypeer); instead it should be a
331
+ # fully-qualified external SIP URI that the caller can independently reach.
332
+ #
333
+ # @param [String] to the target to redirect to, eg a SIP URI
334
+ # @param [Hash, optional] headers a set of headers to send along with the redirect instruction
335
+ def redirect(to, headers = nil)
336
+ write_and_await_response Punchblock::Command::Redirect.new(to: to, headers: headers)
337
+ rescue Punchblock::ProtocolError => e
338
+ abort e
307
339
  end
308
340
 
309
341
  def hangup(headers = nil)
@@ -311,6 +343,8 @@ module Adhearsion
311
343
  logger.info "Hanging up"
312
344
  @end_reason = true
313
345
  write_and_await_response Punchblock::Command::Hangup.new(:headers => headers)
346
+ rescue Punchblock::ProtocolError => e
347
+ abort e
314
348
  end
315
349
 
316
350
  # @private
@@ -349,24 +383,30 @@ module Adhearsion
349
383
  command = Punchblock::Command::Join.new options.merge(join_options_with_target(target))
350
384
  write_and_await_response command
351
385
  {command: command, joined_condition: joined_condition, unjoined_condition: unjoined_condition}
386
+ rescue Punchblock::ProtocolError => e
387
+ abort e
352
388
  end
353
389
 
354
390
  ##
355
391
  # Unjoins this call from another call or a mixer
356
392
  #
357
- # @param [Call, String, Hash] target the target to unjoin from. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
393
+ # @param [Call, String, Hash, nil] target the target to unjoin from. May be a Call object, a call ID (String, Hash), a mixer name (Hash) or missing to unjoin from every existing join (nil)
358
394
  # @option target [String] call_uri The call ID to unjoin from
359
395
  # @option target [String] mixer_name The mixer to unjoin from
360
396
  #
361
- def unjoin(target)
397
+ def unjoin(target = nil)
362
398
  logger.info "Unjoining from #{target}"
363
399
  command = Punchblock::Command::Unjoin.new join_options_with_target(target)
364
400
  write_and_await_response command
401
+ rescue Punchblock::ProtocolError => e
402
+ abort e
365
403
  end
366
404
 
367
405
  # @private
368
406
  def join_options_with_target(target)
369
407
  case target
408
+ when nil
409
+ {}
370
410
  when Call
371
411
  { :call_uri => target.uri }
372
412
  when String
@@ -402,10 +442,14 @@ module Adhearsion
402
442
 
403
443
  def mute
404
444
  write_and_await_response Punchblock::Command::Mute.new
445
+ rescue Punchblock::ProtocolError => e
446
+ abort e
405
447
  end
406
448
 
407
449
  def unmute
408
450
  write_and_await_response Punchblock::Command::Unmute.new
451
+ rescue Punchblock::ProtocolError => e
452
+ abort e
409
453
  end
410
454
 
411
455
  # @private
@@ -1,18 +1,17 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'countdownlatch'
4
+ %w(
5
+ dial
6
+ input
7
+ menu_dsl
8
+ output
9
+ record
10
+ utility
11
+ ).each { |r| require "adhearsion/call_controller/#{r}" }
4
12
 
5
13
  module Adhearsion
6
14
  class CallController
7
- extend ActiveSupport::Autoload
8
-
9
- autoload :Dial
10
- autoload :Input
11
- autoload :MenuDSL
12
- autoload :Output
13
- autoload :Record
14
- autoload :Utility
15
-
16
15
  include Dial
17
16
  include Input
18
17
  include Output
@@ -21,7 +20,7 @@ module Adhearsion
21
20
 
22
21
  class_attribute :callbacks
23
22
 
24
- self.callbacks = {:before_call => [], :after_call => []}
23
+ self.callbacks = {:before_call => [], :after_call => [], :on_error => []}
25
24
 
26
25
  self.callbacks.keys.each do |name|
27
26
  class_eval <<-STOP
@@ -119,9 +118,10 @@ module Adhearsion
119
118
  execute_callbacks :before_call
120
119
  run
121
120
  rescue Call::Hangup, Call::ExpiredError
122
- logger.info "Call was hung up while executing a controller"
123
121
  rescue SyntaxError, StandardError => e
124
122
  Events.trigger :exception, [e, logger]
123
+ on_error e
124
+ raise
125
125
  ensure
126
126
  after_call
127
127
  logger.debug "Finished executing controller #{self.inspect}"
@@ -195,6 +195,12 @@ module Adhearsion
195
195
  @after_call ||= execute_callbacks :after_call
196
196
  end
197
197
 
198
+ # @private
199
+ def on_error(e)
200
+ @error = e
201
+ @on_error ||= execute_callbacks :on_error
202
+ end
203
+
198
204
  # @private
199
205
  def write_and_await_response(command)
200
206
  block_until_resumed
@@ -202,6 +208,7 @@ module Adhearsion
202
208
  if command.is_a?(Punchblock::Component::ComponentNode)
203
209
  command.register_event_handler Punchblock::Event::Complete do |event|
204
210
  @active_components.delete command
211
+ throw :pass
205
212
  end
206
213
  @active_components << command
207
214
  end
@@ -250,6 +257,17 @@ module Adhearsion
250
257
  raise Call::Hangup
251
258
  end
252
259
 
260
+ #
261
+ # Redirect the call to some other target
262
+ #
263
+ # @see Call#redirect
264
+ #
265
+ def redirect(*args)
266
+ block_until_resumed
267
+ call.redirect(*args)
268
+ raise Call::Hangup
269
+ end
270
+
253
271
  #
254
272
  # Mute the call
255
273
  #