adhearsion 2.0.0.alpha2 → 2.0.0.alpha3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|