adhearsion 2.0.0.alpha2 → 2.0.0.alpha3
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.
- data/.gitignore +16 -14
- data/CHANGELOG.md +17 -1
- data/adhearsion.gemspec +14 -13
- data/features/cli_basic.feature +30 -0
- data/features/cli_create.feature +24 -0
- data/features/cli_daemon.feature +21 -0
- data/features/cli_generate.feature +9 -0
- data/features/cli_start.feature +33 -0
- data/features/cli_stop.feature +38 -0
- data/features/controller_generator.feature +19 -0
- data/features/plugin_generator.feature +55 -0
- data/lib/adhearsion.rb +5 -1
- data/lib/adhearsion/call.rb +57 -51
- data/lib/adhearsion/call_controller.rb +4 -20
- data/lib/adhearsion/call_controller/dial.rb +34 -4
- data/lib/adhearsion/calls.rb +4 -1
- data/lib/adhearsion/cli_commands.rb +31 -6
- data/lib/adhearsion/configuration.rb +2 -6
- data/lib/adhearsion/console.rb +56 -17
- data/lib/adhearsion/generators.rb +53 -2
- data/lib/adhearsion/generators/app/app_generator.rb +2 -24
- data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +1 -1
- data/lib/adhearsion/generators/controller/controller_generator.rb +18 -0
- data/lib/adhearsion/generators/controller/templates/lib/controller.rb +4 -0
- data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +3 -0
- data/lib/adhearsion/generators/generator.rb +77 -0
- data/lib/adhearsion/generators/plugin/plugin_generator.rb +33 -0
- data/lib/adhearsion/generators/plugin/templates/.gitignore +9 -0
- data/lib/adhearsion/generators/plugin/templates/Gemfile.tt +4 -0
- data/lib/adhearsion/generators/plugin/templates/README.md.tt +2 -0
- data/lib/adhearsion/generators/plugin/templates/Rakefile.tt +1 -0
- data/lib/adhearsion/generators/plugin/templates/lib/plugin-template.rb.tt +5 -0
- data/lib/adhearsion/generators/plugin/templates/lib/plugin-template/controller_methods.rb.tt +10 -0
- data/lib/adhearsion/generators/plugin/templates/lib/plugin-template/plugin.rb.tt +29 -0
- data/lib/adhearsion/generators/plugin/templates/lib/plugin-template/version.rb.tt +3 -0
- data/lib/adhearsion/generators/plugin/templates/plugin-template.gemspec.tt +35 -0
- data/lib/adhearsion/generators/plugin/templates/spec/plugin-template/controller_methods_spec.rb.tt +26 -0
- data/lib/adhearsion/generators/plugin/templates/spec/spec_helper.rb.tt +13 -0
- data/lib/adhearsion/initializer.rb +14 -22
- data/lib/adhearsion/logging.rb +25 -16
- data/lib/adhearsion/outbound_call.rb +3 -3
- data/lib/adhearsion/plugin.rb +14 -0
- data/lib/adhearsion/punchblock_plugin.rb +6 -1
- data/lib/adhearsion/punchblock_plugin/initializer.rb +8 -8
- data/lib/adhearsion/tasks/configuration.rb +1 -1
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +108 -17
- data/spec/adhearsion/call_controller_spec.rb +7 -64
- data/spec/adhearsion/call_spec.rb +48 -29
- data/spec/adhearsion/calls_spec.rb +7 -0
- data/spec/adhearsion/configuration_spec.rb +14 -14
- data/spec/adhearsion/console_spec.rb +124 -4
- data/spec/adhearsion/generators_spec.rb +17 -0
- data/spec/adhearsion/initializer_spec.rb +22 -18
- data/spec/adhearsion/logging_spec.rb +78 -48
- data/spec/adhearsion/outbound_call_spec.rb +6 -15
- data/spec/adhearsion/plugin_spec.rb +18 -0
- data/spec/adhearsion/process_spec.rb +10 -1
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +8 -6
- data/spec/spec_helper.rb +5 -2
- data/spec/support/call_controller_test_helpers.rb +1 -1
- data/spec/support/initializer_stubs.rb +1 -1
- metadata +106 -66
- data/features/cli.feature +0 -108
- data/lib/adhearsion/initializer/logging.rb +0 -33
- data/spec/adhearsion/initializer/logging_spec.rb +0 -55
@@ -34,16 +34,13 @@ module Adhearsion
|
|
34
34
|
end
|
35
35
|
|
36
36
|
class << self
|
37
|
-
def exec(controller
|
38
|
-
return unless controller
|
39
|
-
|
37
|
+
def exec(controller)
|
40
38
|
new_controller = catch :pass_controller do
|
41
|
-
controller.skip_accept! unless fresh_call
|
42
39
|
controller.execute!
|
43
40
|
nil
|
44
41
|
end
|
45
42
|
|
46
|
-
exec new_controller
|
43
|
+
exec new_controller if new_controller
|
47
44
|
end
|
48
45
|
|
49
46
|
##
|
@@ -57,7 +54,7 @@ module Adhearsion
|
|
57
54
|
|
58
55
|
delegate :[], :[]=, :to => :@metadata
|
59
56
|
delegate :variables, :logger, :to => :call
|
60
|
-
delegate :write_and_await_response, :
|
57
|
+
delegate :write_and_await_response, :answer, :reject, :mute, :unmute, :join, :to => :call
|
61
58
|
|
62
59
|
def initialize(call, metadata = nil, &block)
|
63
60
|
@call, @metadata, @block = call, metadata || {}, block
|
@@ -65,7 +62,6 @@ module Adhearsion
|
|
65
62
|
|
66
63
|
def execute!(*options)
|
67
64
|
execute_callbacks :before_call
|
68
|
-
accept if auto_accept?
|
69
65
|
run
|
70
66
|
rescue Hangup
|
71
67
|
logger.info "Call was hung up"
|
@@ -96,24 +92,12 @@ module Adhearsion
|
|
96
92
|
end
|
97
93
|
end
|
98
94
|
|
99
|
-
def skip_accept!
|
100
|
-
@skip_accept = true
|
101
|
-
end
|
102
|
-
|
103
|
-
def skip_accept?
|
104
|
-
@skip_accept || false
|
105
|
-
end
|
106
|
-
|
107
|
-
def auto_accept?
|
108
|
-
Adhearsion.config.platform.automatically_accept_incoming_calls && !skip_accept?
|
109
|
-
end
|
110
|
-
|
111
95
|
def after_call
|
112
96
|
@after_call ||= execute_callbacks :after_call
|
113
97
|
end
|
114
98
|
|
115
99
|
def hangup(headers = nil)
|
116
|
-
hangup_response = call.hangup
|
100
|
+
hangup_response = call.hangup headers
|
117
101
|
after_call unless hangup_response == false
|
118
102
|
end
|
119
103
|
|
@@ -31,23 +31,43 @@ module Adhearsion
|
|
31
31
|
# dial "IAX2/my.id@voipjet/19095551234", :from => "John Doe <9095551234>"
|
32
32
|
#
|
33
33
|
def dial(to, options = {}, latch = nil)
|
34
|
-
|
34
|
+
targets = Array(to)
|
35
|
+
|
36
|
+
latch ||= CountDownLatch.new targets.size
|
37
|
+
|
38
|
+
call.on_end { |_| latch.countdown! until latch.count == 0 }
|
35
39
|
|
36
40
|
_for = options.delete :for
|
37
41
|
options[:timeout] ||= _for if _for
|
38
42
|
|
39
|
-
|
43
|
+
options[:from] ||= call.from
|
44
|
+
|
45
|
+
calls = targets.map do |target|
|
40
46
|
new_call = OutboundCall.new options
|
41
47
|
|
42
48
|
new_call.on_answer do |event|
|
43
49
|
calls.each do |call_to_hangup, target|
|
44
|
-
|
50
|
+
begin
|
51
|
+
next if call_to_hangup.id == new_call.id
|
52
|
+
logger.debug "Hanging up call #{call_to_hangup.id} because it was not the first to answer a #dial"
|
53
|
+
call_to_hangup.hangup
|
54
|
+
rescue Celluloid::DeadActorError
|
55
|
+
# This actor may previously have been shut down due to the call ending
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
new_call.register_event_handler Punchblock::Event::Unjoined, :other_call_id => call.id do |event|
|
60
|
+
new_call[:"dial_countdown_#{call.id}"] = true
|
61
|
+
latch.countdown!
|
62
|
+
throw :pass
|
45
63
|
end
|
64
|
+
|
65
|
+
logger.debug "Joining call #{new_call.id} to #{call.id} due to a #dial"
|
46
66
|
new_call.join call
|
47
67
|
end
|
48
68
|
|
49
69
|
new_call.on_end do |event|
|
50
|
-
latch.countdown!
|
70
|
+
latch.countdown! unless new_call[:"dial_countdown_#{call.id}"]
|
51
71
|
end
|
52
72
|
|
53
73
|
[new_call, target]
|
@@ -60,6 +80,16 @@ module Adhearsion
|
|
60
80
|
|
61
81
|
timeout = latch.wait options[:timeout]
|
62
82
|
|
83
|
+
logger.debug "#dial finished. Hanging up #{calls.size} outbound calls #{calls.inspect}."
|
84
|
+
calls.each do |outbound_call|
|
85
|
+
begin
|
86
|
+
logger.debug "Hanging up #{outbound_call} because the #dial that created it is complete."
|
87
|
+
outbound_call.hangup
|
88
|
+
rescue Celluloid::DeadActorError
|
89
|
+
# This actor may previously have been shut down due to the call ending
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
63
93
|
return timeout unless timeout
|
64
94
|
|
65
95
|
calls.size == 1 ? calls.first : calls
|
data/lib/adhearsion/calls.rb
CHANGED
@@ -28,9 +28,22 @@ module Adhearsion
|
|
28
28
|
|
29
29
|
desc "create /path/to/directory", "Create a new Adhearsion application under the given path"
|
30
30
|
def create(path)
|
31
|
-
require 'adhearsion/generators'
|
32
31
|
require 'adhearsion/generators/app/app_generator'
|
33
|
-
|
32
|
+
Generators::AppGenerator.start
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "generate [generator_name] arguments", "Invoke a generator"
|
36
|
+
def generate(generator_name = nil, *args)
|
37
|
+
require 'adhearsion/generators/controller/controller_generator'
|
38
|
+
Generators.add_generator :controller, Adhearsion::Generators::ControllerGenerator
|
39
|
+
require 'adhearsion/generators/plugin/plugin_generator'
|
40
|
+
Generators.add_generator :plugin, Adhearsion::Generators::PluginGenerator
|
41
|
+
|
42
|
+
if generator_name
|
43
|
+
Generators.invoke generator_name
|
44
|
+
else
|
45
|
+
Generators.help
|
46
|
+
end
|
34
47
|
end
|
35
48
|
|
36
49
|
desc "version", "Shows Adhearsion version"
|
@@ -55,13 +68,16 @@ module Adhearsion
|
|
55
68
|
def stop(path = nil)
|
56
69
|
execute_from_app_dir! path
|
57
70
|
|
71
|
+
path ||= '.'
|
72
|
+
|
58
73
|
pid_file = if options[:pidfile]
|
59
|
-
File.
|
60
|
-
|
61
|
-
|
74
|
+
File.exists?(File.expand_path(options[:pidfile])) ?
|
75
|
+
options[:pidfile] :
|
76
|
+
File.join(path, options[:pidfile])
|
62
77
|
else
|
63
|
-
path
|
78
|
+
File.join path, Adhearsion::Initializer::DEFAULT_PID_FILE_NAME
|
64
79
|
end
|
80
|
+
pid_file = File.expand_path pid_file
|
65
81
|
|
66
82
|
begin
|
67
83
|
pid = File.read(pid_file).to_i
|
@@ -79,6 +95,8 @@ module Adhearsion
|
|
79
95
|
::Process.kill "KILL", pid
|
80
96
|
rescue Errno::ESRCH
|
81
97
|
end
|
98
|
+
|
99
|
+
File.delete pid_file
|
82
100
|
end
|
83
101
|
|
84
102
|
desc "restart </path/to/directory>", "Restart the Adhearsion server"
|
@@ -144,6 +162,13 @@ module Adhearsion
|
|
144
162
|
end
|
145
163
|
end
|
146
164
|
|
165
|
+
class UnknownGeneratorError < Thor::Error
|
166
|
+
def initialize(gentype)
|
167
|
+
puts "Please specify generator to use (#{Adhearsion::Generators.mappings.keys.join(", ")})"
|
168
|
+
super "Unknown command: #{gentype}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
147
172
|
class PathInvalid < Thor::Error
|
148
173
|
def initialize(path)
|
149
174
|
super "Directory #{path} does not belong to an Adhearsion project!"
|
@@ -21,15 +21,11 @@ module Adhearsion
|
|
21
21
|
root nil, :desc => "Adhearsion application root folder"
|
22
22
|
|
23
23
|
lib "lib", :desc => <<-__
|
24
|
-
Folder to include the own libraries to be used. Adhearsion loads any ruby file
|
25
|
-
located into this folder during the bootstrap process. Set to nil if you do not
|
24
|
+
Folder to include the own libraries to be used. Adhearsion loads any ruby file
|
25
|
+
located into this folder during the bootstrap process. Set to nil if you do not
|
26
26
|
want these files to be loaded. This folder is relative to the application root folder.
|
27
27
|
__
|
28
28
|
|
29
|
-
automatically_accept_incoming_calls true, :transform => Proc.new { |v| v == 'true' }, :desc => <<-__
|
30
|
-
Adhearsion will accept automatically any inbound call
|
31
|
-
__
|
32
|
-
|
33
29
|
environment :development, :transform => Proc.new { |v| v.to_sym }, :desc => <<-__
|
34
30
|
Active environment. Supported values: development, production, staging, test
|
35
31
|
__
|
data/lib/adhearsion/console.rb
CHANGED
@@ -2,9 +2,10 @@ require 'pry'
|
|
2
2
|
|
3
3
|
module Adhearsion
|
4
4
|
class Console
|
5
|
-
include Adhearsion
|
6
5
|
include Singleton
|
7
6
|
|
7
|
+
delegate :silence!, :unsilence!, :to => Adhearsion::Logging
|
8
|
+
|
8
9
|
class << self
|
9
10
|
##
|
10
11
|
# Include another external functionality into the console
|
@@ -17,6 +18,12 @@ module Adhearsion
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
21
|
+
attr_accessor :input
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@input = $stdin
|
25
|
+
end
|
26
|
+
|
20
27
|
##
|
21
28
|
# Start the Adhearsion console
|
22
29
|
#
|
@@ -48,21 +55,47 @@ module Adhearsion
|
|
48
55
|
logger.info "Shutting down"
|
49
56
|
end
|
50
57
|
|
58
|
+
def log_level(level = nil)
|
59
|
+
if level
|
60
|
+
Adhearsion::Logging.level = level
|
61
|
+
else
|
62
|
+
::Logging::LEVELS.invert[Adhearsion::Logging.level].to_sym
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def shutdown!
|
67
|
+
Process.shutdown!
|
68
|
+
end
|
69
|
+
|
51
70
|
def calls
|
52
71
|
Adhearsion.active_calls
|
53
72
|
end
|
54
73
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
74
|
+
def take(call = nil)
|
75
|
+
case call
|
76
|
+
when Call
|
77
|
+
interact_with_call call
|
78
|
+
when String
|
79
|
+
if call = calls[call]
|
80
|
+
interact_with_call call
|
81
|
+
else
|
82
|
+
logger.error "An active call with that ID does not exist"
|
83
|
+
end
|
84
|
+
when nil
|
85
|
+
if calls.size == 1
|
86
|
+
interact_with_call calls.values.first
|
87
|
+
else
|
88
|
+
puts "Please choose a call:"
|
89
|
+
current_calls = calls.values
|
90
|
+
current_calls.each_with_index do |call, index|
|
91
|
+
puts "#{index}. (#{call.is_a?(OutboundCall) ? 'o' : 'i' }) #{call.id} from #{call.from} to #{call.to}"
|
92
|
+
end
|
93
|
+
index = input.gets.chomp.to_i
|
94
|
+
call = current_calls[index]
|
95
|
+
interact_with_call call
|
96
|
+
end
|
97
|
+
else
|
98
|
+
raise ArgumentError
|
66
99
|
end
|
67
100
|
end
|
68
101
|
|
@@ -76,12 +109,18 @@ module Adhearsion
|
|
76
109
|
end
|
77
110
|
end
|
78
111
|
|
79
|
-
|
80
|
-
|
112
|
+
private
|
113
|
+
|
114
|
+
def interact_with_call(call)
|
115
|
+
Pry.prompt = [ proc { "AHN<#{call.id}> " },
|
116
|
+
proc { "AHN<#{call.id}? " } ]
|
117
|
+
|
118
|
+
CallController.exec InteractiveController.new(call)
|
119
|
+
end
|
81
120
|
|
82
|
-
|
83
|
-
|
84
|
-
|
121
|
+
class InteractiveController < CallController
|
122
|
+
def run
|
123
|
+
pry
|
85
124
|
end
|
86
125
|
end
|
87
126
|
end
|
@@ -1,5 +1,56 @@
|
|
1
1
|
module Adhearsion
|
2
2
|
module Generators
|
3
3
|
extend ActiveSupport::Autoload
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
autoload :Generator
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# Show help message with available generators.
|
10
|
+
def help(command = 'generate')
|
11
|
+
puts "Usage: ahn #{command} GENERATOR_NAME [args] [options]"
|
12
|
+
puts
|
13
|
+
puts "Please choose a generator below."
|
14
|
+
puts
|
15
|
+
|
16
|
+
mappings.each_pair do |name, klass|
|
17
|
+
puts name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def invoke(generator_name, args = ARGV)
|
22
|
+
klass = Generators.mappings[generator_name.to_sym]
|
23
|
+
raise UnknownGeneratorError, generator_name unless klass
|
24
|
+
|
25
|
+
args << "--help" if args.empty? && klass.arguments.any?(&:required?)
|
26
|
+
|
27
|
+
klass.start args
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Return a ordered list of task with their class
|
32
|
+
#
|
33
|
+
def mappings
|
34
|
+
@_mappings ||= Hash.new
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Globally add a new generator class to +ahn generate+
|
39
|
+
#
|
40
|
+
# @param [Symbol] name
|
41
|
+
# key name for generator mapping
|
42
|
+
# @param [Class] klass
|
43
|
+
# class of generator
|
44
|
+
#
|
45
|
+
# @return [Hash] generator mappings
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# Adhearsion::Generators.add_generator :myplugin, MyPluginGenerator
|
49
|
+
#
|
50
|
+
def add_generator(name, klass)
|
51
|
+
mappings[name] = klass
|
52
|
+
end
|
53
|
+
|
54
|
+
end#class << self
|
55
|
+
end#module
|
56
|
+
end#module
|
@@ -1,33 +1,11 @@
|
|
1
|
-
begin
|
2
|
-
require 'thor/group'
|
3
|
-
rescue LoadError
|
4
|
-
puts "Thor is not available.\nIf you ran this command from a git checkout " \
|
5
|
-
"of Adhearsion, please make sure thor is installed,\nand run this command " \
|
6
|
-
"as `ruby #{$0} #{(ARGV | ['--dev']).join(" ")}`"
|
7
|
-
exit
|
8
|
-
end
|
9
|
-
|
10
1
|
module Adhearsion
|
11
2
|
module Generators
|
12
|
-
class AppGenerator <
|
13
|
-
include Thor::Actions
|
3
|
+
class AppGenerator < Generator
|
14
4
|
|
15
5
|
BASEDIRS = %w( config lib script )
|
16
6
|
|
17
|
-
argument :app_action, :type => :string
|
18
|
-
argument :app_path, :type => :string
|
19
|
-
|
20
|
-
def self.source_root(path = nil)
|
21
|
-
path = File.join(base_root, 'templates')
|
22
|
-
path if File.exists?(path)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.base_root
|
26
|
-
File.dirname(__FILE__)
|
27
|
-
end
|
28
|
-
|
29
7
|
def setup_project
|
30
|
-
self.destination_root = @
|
8
|
+
self.destination_root = @generator_name
|
31
9
|
BASEDIRS.each { |dir| directory dir }
|
32
10
|
template "Gemfile.erb", "Gemfile"
|
33
11
|
copy_file "gitignore", ".gitignore"
|
@@ -29,7 +29,7 @@ Adhearsion.config do |config|
|
|
29
29
|
##
|
30
30
|
# Use with Asterisk
|
31
31
|
#
|
32
|
-
# config.punchblock.platform = :asterisk #
|
32
|
+
# config.punchblock.platform = :asterisk # Use Asterisk
|
33
33
|
# config.punchblock.username = "" # Your AMI username
|
34
34
|
# config.punchblock.password = "" # Your AMI password
|
35
35
|
# config.punchblock.host = "127.0.0.1" # Your AMI host
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module Generators
|
3
|
+
class ControllerGenerator < Generator
|
4
|
+
|
5
|
+
argument :controller_name, :type => :string
|
6
|
+
|
7
|
+
def create_controller
|
8
|
+
raise Exception, "Generator commands need to be run in an Adhearsion app directory" unless ScriptAhnLoader.in_ahn_application?('.')
|
9
|
+
self.destination_root = '.'
|
10
|
+
empty_directory 'lib'
|
11
|
+
empty_directory 'spec'
|
12
|
+
template 'lib/controller.rb', "lib/#{@controller_name.underscore}.rb"
|
13
|
+
template 'spec/controller_spec.rb', "spec/#{@controller_name.underscore}_spec.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|