adhearsion 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.travis.yml +4 -3
  2. data/CHANGELOG.md +30 -0
  3. data/README.markdown +1 -0
  4. data/adhearsion.gemspec +3 -4
  5. data/bin/ahn +0 -20
  6. data/features/cli_create.feature +1 -1
  7. data/features/cli_restart.feature +25 -1
  8. data/features/cli_start.feature +0 -2
  9. data/features/plugin_generator.feature +66 -15
  10. data/features/support/env.rb +0 -13
  11. data/lib/adhearsion.rb +26 -6
  12. data/lib/adhearsion/call.rb +42 -7
  13. data/lib/adhearsion/call_controller.rb +5 -2
  14. data/lib/adhearsion/call_controller/dial.rb +92 -50
  15. data/lib/adhearsion/call_controller/input.rb +19 -6
  16. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +4 -0
  17. data/lib/adhearsion/call_controller/output.rb +143 -161
  18. data/lib/adhearsion/call_controller/output/abstract_player.rb +30 -0
  19. data/lib/adhearsion/call_controller/output/async_player.rb +26 -0
  20. data/lib/adhearsion/call_controller/output/formatter.rb +81 -0
  21. data/lib/adhearsion/call_controller/output/player.rb +25 -0
  22. data/lib/adhearsion/call_controller/record.rb +19 -2
  23. data/lib/adhearsion/events.rb +3 -0
  24. data/lib/adhearsion/foundation.rb +12 -6
  25. data/lib/adhearsion/foundation/exception_handler.rb +8 -6
  26. data/lib/adhearsion/generators/app/templates/README.md +13 -0
  27. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +7 -1
  28. data/lib/adhearsion/generators/plugin/plugin_generator.rb +1 -0
  29. data/lib/adhearsion/generators/plugin/templates/plugin-template.gemspec.tt +3 -7
  30. data/lib/adhearsion/generators/plugin/templates/spec/spec_helper.rb.tt +0 -1
  31. data/lib/adhearsion/outbound_call.rb +15 -5
  32. data/lib/adhearsion/punchblock_plugin.rb +13 -2
  33. data/lib/adhearsion/punchblock_plugin/initializer.rb +13 -12
  34. data/lib/adhearsion/router.rb +43 -2
  35. data/lib/adhearsion/router/evented_route.rb +15 -0
  36. data/lib/adhearsion/router/openended_route.rb +16 -0
  37. data/lib/adhearsion/router/route.rb +31 -13
  38. data/lib/adhearsion/router/unaccepting_route.rb +11 -0
  39. data/lib/adhearsion/version.rb +1 -1
  40. data/pre-commit +14 -1
  41. data/spec/adhearsion/call_controller/dial_spec.rb +105 -10
  42. data/spec/adhearsion/call_controller/input_spec.rb +19 -21
  43. data/spec/adhearsion/call_controller/output/async_player_spec.rb +67 -0
  44. data/spec/adhearsion/call_controller/output/formatter_spec.rb +90 -0
  45. data/spec/adhearsion/call_controller/output/player_spec.rb +65 -0
  46. data/spec/adhearsion/call_controller/output_spec.rb +436 -190
  47. data/spec/adhearsion/call_controller/record_spec.rb +49 -6
  48. data/spec/adhearsion/call_controller_spec.rb +10 -2
  49. data/spec/adhearsion/call_spec.rb +138 -0
  50. data/spec/adhearsion/calls_spec.rb +1 -1
  51. data/spec/adhearsion/outbound_call_spec.rb +48 -8
  52. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +34 -23
  53. data/spec/adhearsion/router/evented_route_spec.rb +34 -0
  54. data/spec/adhearsion/router/openended_route_spec.rb +61 -0
  55. data/spec/adhearsion/router/route_spec.rb +26 -4
  56. data/spec/adhearsion/router/unaccepting_route_spec.rb +72 -0
  57. data/spec/adhearsion/router_spec.rb +107 -2
  58. data/spec/adhearsion_spec.rb +19 -0
  59. data/spec/capture_warnings.rb +28 -21
  60. data/spec/spec_helper.rb +2 -3
  61. data/spec/support/call_controller_test_helpers.rb +31 -30
  62. metadata +32 -29
@@ -1,10 +1,11 @@
1
1
  language: ruby
2
+ script: bundle exec rake --trace
2
3
  rvm:
3
4
  - 1.9.2
4
5
  - 1.9.3
5
- - jruby-19mode # JRuby in 1.9 mode
6
- - rbx-19mode # currently in active development, may or may not work for your project
7
- - ruby-head
6
+ # - jruby-19mode # JRuby in 1.9 mode
7
+ # - rbx-19mode # currently in active development, may or may not work for your project
8
+ # - ruby-head
8
9
  env: ARUBA_TIMEOUT=120 RAILS_ENV=development AHN_ENV=development
9
10
  notifications:
10
11
  irc: "irc.freenode.org#adhearsion"
@@ -1,5 +1,35 @@
1
1
  # [develop](https://github.com/adhearsion/adhearsion)
2
2
 
3
+ # [2.1.0](https://github.com/adhearsion/adhearsion/compare/v2.0.1...v2.1.0) - [2012-08-07](https://rubygems.org/gems/adhearsion/versions/2.1.0)
4
+
5
+ ## Features
6
+ * Initial support for FreeSWITCH
7
+ * Added the possibility to specify a confirmation controller on `#dial` operations
8
+ * Allow specifying a controller to run when originating an outbound call
9
+ * Allow `Call#execute_controller` to take a block instead of a controller instance. Simplifies event-based execution of simple controllers (eg whisper into a call)
10
+ * Allow route modifiers such that they:
11
+ * Do not accept calls that match
12
+ * Do not execute a controller
13
+ * Do not hangup after controller execution
14
+ * Permit asynchronous output using bang version of methods (eg `CallController#play!`), returning an output component, which can be stopped
15
+ * Added `CallController#safely` which will catch and log `StandardError` in a call controller, but will not allow it to crash the controller
16
+ * `CallController#record` now has an `:interruptible` option that allows recording to be stopped by pressing any DTMF key
17
+ * Added `Call#on_joined` and `Call#on_unjoined` for easily registering joined/unjoined handlers
18
+ * `Adhearsion.root` and `Adhearsion.root=` are now available to return the root path to the application. `Adhearsion.ahn_root=` is deprecated
19
+ * `Adhearsion.deprecated` added for internal use to clearly mark deprecated methods
20
+
21
+ ## Bugfixes
22
+ * All output methods will now raise `Adhearsion::CallController::Output::PlaybackError` when output fails, instead of failing silently
23
+ * `CallController#hangup` now prevents further execution of the controller
24
+ * Calls which do not match any routes are rejected with an error
25
+ * Calls are not accepted until a matching route is found
26
+ * Give sensible dependency defaults for generated plugins
27
+ * Fixed mocha-fail in generated plugins
28
+ * Plugins generated with a snake_case name did not have the appropriate constants camelized
29
+ * `CallController#dial` no longer creates outbound calls if the dialing party hangs up before it executes
30
+ * `CallController#ask` no longer loops on timeout
31
+ * Correct default port for Asterisk
32
+
3
33
  # [2.0.1](https://github.com/adhearsion/adhearsion/compare/v2.0.0...v2.0.1) - [2012-06-04](https://rubygems.org/gems/adhearsion/versions/2.0.1)
4
34
  * Bugfix: Avoid infinitely recursive exception handlers
5
35
  * Bugfix: Don't require rubygems where we don't need it
@@ -20,6 +20,7 @@ Adhearsion rests above a lower-level telephony platform, for example [Asterisk](
20
20
  * Ruby 1.9.2+ or JRuby 1.6.7+
21
21
  * A VoIP platform:
22
22
  * Asterisk 1.8+
23
+ * FreeSWITCH
23
24
  * Prism 11+ with rayo-server
24
25
  * An interest in building cool new things
25
26
 
@@ -30,19 +30,18 @@ Gem::Specification.new do |s|
30
30
  s.add_runtime_dependency 'jruby-openssl' if RUBY_PLATFORM == 'java'
31
31
  s.add_runtime_dependency 'logging', [">= 1.6.1"]
32
32
  s.add_runtime_dependency 'pry'
33
- s.add_runtime_dependency 'punchblock', ["~> 1.0"]
33
+ s.add_runtime_dependency 'punchblock', ["~> 1.4"]
34
34
  s.add_runtime_dependency 'rake'
35
35
  s.add_runtime_dependency 'ruby_speech', ["~> 1.0"]
36
36
  s.add_runtime_dependency 'thor'
37
- s.add_runtime_dependency 'uuid'
38
37
 
39
- s.add_development_dependency 'aruba'
38
+ s.add_development_dependency 'aruba', "~> 0.4"
40
39
  s.add_development_dependency 'ci_reporter'
41
40
  s.add_development_dependency 'cucumber'
42
41
  s.add_development_dependency 'flexmock'
43
42
  s.add_development_dependency 'guard-cucumber'
44
43
  s.add_development_dependency 'guard-rspec'
45
- s.add_development_dependency 'rspec', ["~> 2.7.0"]
44
+ s.add_development_dependency 'rspec', ["~> 2.11.0"]
46
45
  s.add_development_dependency 'ruby_gntp'
47
46
  s.add_development_dependency 'simplecov'
48
47
  s.add_development_dependency 'simplecov-rcov'
data/bin/ahn CHANGED
@@ -1,24 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # This is the main executable file.
4
-
5
- # Adhearsion, open source collaboration framework
6
- # Copyright (C) 2006,2007,2008 Jay Phillips
7
- #
8
- # This library is free software; you can redistribute it and/or modify it under
9
- # the terms of the GNU Lesser General Public License as published by the Free
10
- # Software Foundation; either version 2.1 of the License, or (at your option)
11
- # any later version.
12
- #
13
- # This library is distributed in the hope that it will be useful, but WITHOUT
14
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15
- # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16
- # details.
17
- #
18
- # You should have received a copy of the GNU Lesser General Public License along
19
- # with this library; if not, write to the Free Software Foundation, Inc.,
20
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
-
22
3
  require 'adhearsion/cli'
23
-
24
4
  Adhearsion::CLI::AhnCommand.start
@@ -19,6 +19,6 @@ Feature: Adhearsion Ahn CLI (Create)
19
19
  When I run `ahn create`
20
20
  Then the output should contain:
21
21
  """
22
- "create" was called incorrectly. Call as "ahn create /path/to/directory".
22
+ ahn create requires at least 1 argument: "ahn create /path/to/directory".
23
23
  """
24
24
  And the exit status should be 1
@@ -1,4 +1,4 @@
1
- Feature: Adhearsion Ahn CLI (stop)
1
+ Feature: Adhearsion Ahn CLI (restart)
2
2
  As an Adhearsion user
3
3
  I want the ahn command to provide a 'restart' command
4
4
  So that I can restart a running Adhearsion daemon
@@ -17,3 +17,27 @@ Feature: Adhearsion Ahn CLI (stop)
17
17
  """
18
18
  Starting Adhearsion
19
19
  """
20
+
21
+ @reconnect
22
+ Scenario: Command restart with no path outside of the app directory
23
+ Given that I create a valid app under "path/somewhere"
24
+ When I run `ahn daemon path/somewhere --pid-file=ahn.pid`
25
+ And I run `ahn restart --pid-file=ahn.pid`
26
+ Then the output should contain:
27
+ """
28
+ A valid path is required for restart, unless run from an Adhearson app directory
29
+ """
30
+ And the exit status should be 1
31
+
32
+ @reconnect
33
+ Scenario: Command restart with no path inside of the app directory
34
+ Given JRuby skip test
35
+ Given that I create a valid app under "path/somewhere"
36
+ When I cd to "path/somewhere"
37
+ And I run `ahn daemon --pid-file=ahn.pid`
38
+ And I run `ahn restart --pid-file=ahn.pid`
39
+ Then the output should contain:
40
+ """
41
+ Starting Adhearsion
42
+ """
43
+ And the exit status should be 0
@@ -18,7 +18,6 @@ Feature: Adhearsion Ahn CLI (start)
18
18
  And I run `ahn start` interactively
19
19
  And I wait for output to contain "Starting connection to server"
20
20
  Then the output should contain "Adhearsion::Console: Launching Adhearsion Console"
21
- And the output should contain "AHN>"
22
21
  And the output should contain "Adhearsion shut down"
23
22
 
24
23
  Scenario: Command start with only path works properly
@@ -27,5 +26,4 @@ Feature: Adhearsion Ahn CLI (start)
27
26
  When I run `ahn start path/somewhere` interactively
28
27
  And I wait for output to contain "Starting connection to server"
29
28
  Then the output should contain "Adhearsion::Console: Launching Adhearsion Console"
30
- And the output should contain "AHN>"
31
29
  And the output should contain "Adhearsion shut down"
@@ -3,29 +3,80 @@ Feature: Adhearsion plugin generator
3
3
  As an Adhearsion plugin developer
4
4
  I want to generate a plugin and its basic structure
5
5
 
6
- Scenario: Generate the basic structure for a plugin
6
+ Scenario: Generate the basic structure for a plugin with a constant name
7
7
  When I run `ahn generate plugin TestPlugin`
8
8
  Then the following directories should exist:
9
- | test_plugin |
10
- | test_plugin/lib |
11
- | test_plugin/lib/test_plugin |
12
- | test_plugin/spec |
9
+ | test_plugin |
10
+ | test_plugin/lib |
11
+ | test_plugin/lib/test_plugin |
12
+ | test_plugin/spec |
13
13
  And the following files should exist:
14
- | test_plugin/test_plugin.gemspec |
15
- | test_plugin/Rakefile |
16
- | test_plugin/README.md |
17
- | test_plugin/Gemfile |
18
- | test_plugin/lib/test_plugin.rb |
19
- | test_plugin/lib/test_plugin/version.rb |
20
- | test_plugin/lib/test_plugin/plugin.rb |
21
- | test_plugin/lib/test_plugin/controller_methods.rb |
22
- | test_plugin/spec/spec_helper.rb |
23
- | test_plugin/spec/test_plugin/controller_methods_spec.rb |
14
+ | test_plugin/test_plugin.gemspec |
15
+ | test_plugin/Rakefile |
16
+ | test_plugin/README.md |
17
+ | test_plugin/Gemfile |
18
+ | test_plugin/lib/test_plugin.rb |
19
+ | test_plugin/lib/test_plugin/version.rb |
20
+ | test_plugin/lib/test_plugin/plugin.rb |
21
+ | test_plugin/lib/test_plugin/controller_methods.rb |
22
+ | test_plugin/spec/spec_helper.rb |
23
+ | test_plugin/spec/test_plugin/controller_methods_spec.rb |
24
24
  And the file "test_plugin/test_plugin.gemspec" should contain "test_plugin/version"
25
25
  And the file "test_plugin/README.md" should contain "TestPlugin"
26
26
  And the file "test_plugin/lib/test_plugin.rb" should contain each of these content parts:
27
27
  """
28
+ TestPlugin
29
+ test_plugin/version
30
+ test_plugin/plugin
31
+ test_plugin/controller_methods
32
+ """
33
+ And the file "test_plugin/lib/test_plugin/version.rb" should contain each of these content parts:
34
+ """
28
35
  module TestPlugin
36
+ VERSION
37
+ """
38
+ And the file "test_plugin/lib/test_plugin/plugin.rb" should contain each of these content parts:
39
+ """
40
+ module TestPlugin
41
+ init :test_plugin
42
+ config :test_plugin
43
+ namespace :test_plugin
44
+ """
45
+ And the file "test_plugin/lib/test_plugin/controller_methods.rb" should contain each of these content parts:
46
+ """
47
+ module TestPlugin
48
+ def greet
49
+ """
50
+ And the file "test_plugin/spec/spec_helper.rb" should contain "require 'test_plugin'"
51
+ And the file "test_plugin/spec/test_plugin/controller_methods_spec.rb" should contain each of these content parts:
52
+ """
53
+ module TestPlugin
54
+ include TestPlugin::ControllerMethods
55
+ """
56
+
57
+ Scenario: Generate the basic structure for a plugin with an underscored name
58
+ When I run `ahn generate plugin test_plugin`
59
+ Then the following directories should exist:
60
+ | test_plugin |
61
+ | test_plugin/lib |
62
+ | test_plugin/lib/test_plugin |
63
+ | test_plugin/spec |
64
+ And the following files should exist:
65
+ | test_plugin/test_plugin.gemspec |
66
+ | test_plugin/Rakefile |
67
+ | test_plugin/README.md |
68
+ | test_plugin/Gemfile |
69
+ | test_plugin/lib/test_plugin.rb |
70
+ | test_plugin/lib/test_plugin/version.rb |
71
+ | test_plugin/lib/test_plugin/plugin.rb |
72
+ | test_plugin/lib/test_plugin/controller_methods.rb |
73
+ | test_plugin/spec/spec_helper.rb |
74
+ | test_plugin/spec/test_plugin/controller_methods_spec.rb |
75
+ And the file "test_plugin/test_plugin.gemspec" should contain "test_plugin/version"
76
+ And the file "test_plugin/README.md" should contain "TestPlugin"
77
+ And the file "test_plugin/lib/test_plugin.rb" should contain each of these content parts:
78
+ """
79
+ TestPlugin
29
80
  test_plugin/version
30
81
  test_plugin/plugin
31
82
  test_plugin/controller_methods
@@ -1,18 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'simplecov'
4
- require 'simplecov-rcov'
5
- class SimpleCov::Formatter::MergedFormatter
6
- def format(result)
7
- SimpleCov::Formatter::HTMLFormatter.new.format(result)
8
- SimpleCov::Formatter::RcovFormatter.new.format(result)
9
- end
10
- end
11
- SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
12
- SimpleCov.start do
13
- add_filter "/vendor/"
14
- end
15
-
16
3
  JRUBY_OPTS_SAVED=ENV['JRUBY_OPTS']
17
4
  JAVA_OPTS_SAVED=ENV['JAVA_OPTS']
18
5
 
@@ -4,14 +4,9 @@ abort "ERROR: You are running Adhearsion on an unsupported version of Ruby (Ruby
4
4
 
5
5
  %w{
6
6
  active_support/all
7
- uuid
8
- future-resource
9
7
  punchblock
10
- ostruct
11
8
  ruby_speech
12
9
  countdownlatch
13
- has_guarded_handlers
14
- girl_friday
15
10
  loquacious
16
11
  celluloid
17
12
 
@@ -42,16 +37,41 @@ module Adhearsion
42
37
 
43
38
  class << self
44
39
 
45
- def ahn_root=(path)
40
+ #
41
+ # Sets the application path
42
+ # @param[String|Pathname] The application path to set
43
+ #
44
+ def root=(path)
46
45
  Adhearsion.config[:platform].root = path.nil? ? nil : File.expand_path(path)
47
46
  end
48
47
 
48
+ #
49
+ # Returns the current application path
50
+ # @return [Pathname] The application path
51
+ #
52
+ def root
53
+ Adhearsion.config[:platform].root
54
+ end
55
+
56
+ #
57
+ # @deprecated Use #root= instead
58
+ #
59
+ def ahn_root=(path)
60
+ Adhearsion.deprecated "#Adhearsion.root="
61
+ Adhearsion.root = path
62
+ end
63
+
49
64
  def config(&block)
50
65
  @config ||= initialize_config
51
66
  block_given? and yield @config
52
67
  @config
53
68
  end
54
69
 
70
+ def deprecated(new_method)
71
+ logger.info "#{caller[0]} - This method is deprecated, please use #{new_method}."
72
+ logger.warn caller.join("\n")
73
+ end
74
+
55
75
  def initialize_config
56
76
  _config = Configuration.new
57
77
  env = ENV['AHN_ENV'] || ENV['RAILS_ENV']
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'has_guarded_handlers'
3
4
  require 'thread'
4
5
 
5
6
  module Adhearsion
@@ -114,16 +115,14 @@ module Adhearsion
114
115
  throw :pass
115
116
  end
116
117
 
117
- register_event_handler Punchblock::Event::Joined do |event|
118
+ on_joined do |event|
118
119
  target = event.call_id || event.mixer_name
119
120
  signal :joined, target
120
- throw :pass
121
121
  end
122
122
 
123
- register_event_handler Punchblock::Event::Unjoined do |event|
123
+ on_unjoined do |event|
124
124
  target = event.call_id || event.mixer_name
125
125
  signal :unjoined, target
126
- throw :pass
127
126
  end
128
127
 
129
128
  on_end do |event|
@@ -132,6 +131,7 @@ module Adhearsion
132
131
  @end_reason = event.reason
133
132
  commands.terminate
134
133
  after(after_end_hold_time) { current_actor.terminate! }
134
+ throw :pass
135
135
  end
136
136
  end
137
137
 
@@ -140,6 +140,39 @@ module Adhearsion
140
140
  30
141
141
  end
142
142
 
143
+ ##
144
+ # Registers a callback for when this call is joined to another call or a mixer
145
+ #
146
+ # @param [Call, String, Hash, nil] target the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
147
+ # @option target [String] call_id The call ID to guard on
148
+ # @option target [String] mixer_name The mixer name to guard on
149
+ #
150
+ def on_joined(target = nil, &block)
151
+ register_event_handler Punchblock::Event::Joined, *guards_for_target(target) do |event|
152
+ block.call event
153
+ throw :pass
154
+ end
155
+ end
156
+
157
+ ##
158
+ # Registers a callback for when this call is unjoined from another call or a mixer
159
+ #
160
+ # @param [Call, String, Hash, nil] target the target to guard on. May be a Call object, a call ID (String, Hash) or a mixer name (Hash)
161
+ # @option target [String] call_id The call ID to guard on
162
+ # @option target [String] mixer_name The mixer name to guard on
163
+ #
164
+ def on_unjoined(target = nil, &block)
165
+ register_event_handler Punchblock::Event::Unjoined, *guards_for_target(target) do |event|
166
+ block.call event
167
+ throw :pass
168
+ end
169
+ end
170
+
171
+ # @private
172
+ def guards_for_target(target)
173
+ target ? [join_options_with_target(target)] : []
174
+ end
175
+
143
176
  def on_end(&block)
144
177
  register_event_handler Punchblock::Event::End do |event|
145
178
  block.call event
@@ -233,11 +266,11 @@ module Adhearsion
233
266
  end
234
267
 
235
268
  def mute
236
- write_and_await_response ::Punchblock::Command::Mute.new
269
+ write_and_await_response Punchblock::Command::Mute.new
237
270
  end
238
271
 
239
272
  def unmute
240
- write_and_await_response ::Punchblock::Command::Unmute.new
273
+ write_and_await_response Punchblock::Command::Unmute.new
241
274
  end
242
275
 
243
276
  # @private
@@ -287,8 +320,10 @@ module Adhearsion
287
320
  "#<#{self.class}:#{id} #{attrs.join ', '}>"
288
321
  end
289
322
 
290
- def execute_controller(controller, completion_callback = nil)
323
+ def execute_controller(controller = nil, completion_callback = nil, &block)
324
+ raise ArgumentError if controller && block_given?
291
325
  call = current_actor
326
+ controller ||= CallController.new call, &block
292
327
  Thread.new do
293
328
  catching_standard_errors do
294
329
  begin
@@ -139,8 +139,9 @@ module Adhearsion
139
139
  #
140
140
  def hangup(headers = nil)
141
141
  block_until_resumed
142
- hangup_response = call.hangup headers
143
- after_call unless hangup_response == false
142
+ call.hangup headers
143
+ after_call
144
+ raise Call::Hangup
144
145
  end
145
146
 
146
147
  # @private
@@ -221,6 +222,8 @@ module Adhearsion
221
222
  end
222
223
  end
223
224
 
225
+ alias :safely :catching_standard_errors
226
+
224
227
  # @private
225
228
  def block_until_resumed
226
229
  instance_variable_defined?(:@pause_latch) && @pause_latch.wait