adhearsion 2.0.0.alpha1 → 2.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +17 -0
- data/adhearsion.gemspec +4 -3
- data/features/app_generator.feature +3 -1
- data/features/cli.feature +7 -7
- data/features/support/env.rb +46 -0
- data/lib/adhearsion.rb +1 -2
- data/lib/adhearsion/call.rb +59 -19
- data/lib/adhearsion/call_controller.rb +20 -24
- data/lib/adhearsion/call_controller/dial.rb +18 -18
- data/lib/adhearsion/cli_commands.rb +26 -9
- data/lib/adhearsion/configuration.rb +39 -10
- data/lib/adhearsion/console.rb +61 -42
- data/lib/adhearsion/foundation/libc.rb +13 -0
- data/lib/adhearsion/generators/app/app_generator.rb +4 -1
- data/lib/adhearsion/generators/app/templates/{Gemfile → Gemfile.erb} +1 -1
- data/lib/adhearsion/generators/app/templates/Rakefile +3 -22
- data/lib/adhearsion/generators/app/templates/gitignore +7 -0
- data/lib/adhearsion/generators/app/templates/lib/simon_game.rb +1 -0
- data/lib/adhearsion/generators/app/templates/script/ahn +1 -0
- data/lib/adhearsion/initializer.rb +24 -12
- data/lib/adhearsion/linux_proc_name.rb +41 -0
- data/lib/adhearsion/outbound_call.rb +10 -5
- data/lib/adhearsion/plugin.rb +29 -132
- data/lib/adhearsion/process.rb +4 -1
- data/lib/adhearsion/punchblock_plugin.rb +14 -5
- data/lib/adhearsion/punchblock_plugin/initializer.rb +8 -1
- data/lib/adhearsion/router/route.rb +1 -3
- data/lib/adhearsion/tasks.rb +6 -12
- data/lib/adhearsion/tasks/configuration.rb +7 -24
- data/lib/adhearsion/tasks/environment.rb +12 -0
- data/lib/adhearsion/tasks/plugins.rb +9 -14
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +46 -22
- data/spec/adhearsion/call_controller_spec.rb +48 -13
- data/spec/adhearsion/call_spec.rb +144 -23
- data/spec/adhearsion/calls_spec.rb +8 -4
- data/spec/adhearsion/console_spec.rb +24 -0
- data/spec/adhearsion/initializer/logging_spec.rb +0 -3
- data/spec/adhearsion/initializer_spec.rb +52 -37
- data/spec/adhearsion/logging_spec.rb +0 -3
- data/spec/adhearsion/outbound_call_spec.rb +12 -2
- data/spec/adhearsion/plugin_spec.rb +74 -184
- data/spec/adhearsion/process_spec.rb +59 -26
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +3 -4
- data/spec/adhearsion/punchblock_plugin_spec.rb +11 -0
- data/spec/adhearsion/router/route_spec.rb +37 -6
- data/spec/adhearsion_spec.rb +31 -8
- data/spec/spec_helper.rb +14 -0
- data/spec/support/call_controller_test_helpers.rb +2 -2
- data/spec/support/logging_helpers.rb +2 -0
- metadata +85 -68
- data/lib/adhearsion/dialplan_controller.rb +0 -9
- data/lib/adhearsion/foundation/synchronized_hash.rb +0 -93
- data/lib/adhearsion/plugin/methods_container.rb +0 -6
- data/spec/adhearsion/dialplan_controller_spec.rb +0 -26
@@ -2,6 +2,17 @@ require 'fileutils'
|
|
2
2
|
require 'adhearsion/script_ahn_loader'
|
3
3
|
require 'thor'
|
4
4
|
|
5
|
+
class Thor
|
6
|
+
class Task
|
7
|
+
protected
|
8
|
+
|
9
|
+
def sans_backtrace(backtrace, caller) #:nodoc:
|
10
|
+
saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) }
|
11
|
+
saned -= caller
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
5
16
|
module Adhearsion
|
6
17
|
module CLI
|
7
18
|
class AhnCommand < Thor
|
@@ -42,7 +53,7 @@ module Adhearsion
|
|
42
53
|
desc "stop </path/to/directory>", "Stop a running Adhearsion server"
|
43
54
|
method_option :pidfile, :type => :string, :aliases => %w(--pid-file)
|
44
55
|
def stop(path = nil)
|
45
|
-
execute_from_app_dir! path
|
56
|
+
execute_from_app_dir! path
|
46
57
|
|
47
58
|
pid_file = if options[:pidfile]
|
48
59
|
File.expand_path File.exists?(File.expand_path(options[:pidfile])) ?
|
@@ -55,10 +66,10 @@ module Adhearsion
|
|
55
66
|
begin
|
56
67
|
pid = File.read(pid_file).to_i
|
57
68
|
rescue
|
58
|
-
raise
|
69
|
+
raise PIDReadError, pid_file
|
59
70
|
end
|
60
71
|
|
61
|
-
raise
|
72
|
+
raise PIDReadError, pid_file if pid.nil?
|
62
73
|
|
63
74
|
say "Stopping Adhearsion server at #{path} with pid #{pid}"
|
64
75
|
waiting_timeout = Time.now + 15
|
@@ -73,7 +84,7 @@ module Adhearsion
|
|
73
84
|
desc "restart </path/to/directory>", "Restart the Adhearsion server"
|
74
85
|
method_option :pidfile, :type => :string, :aliases => %w(--pid-file)
|
75
86
|
def restart(path = nil)
|
76
|
-
execute_from_app_dir! path
|
87
|
+
execute_from_app_dir! path
|
77
88
|
invoke :stop
|
78
89
|
invoke :daemon
|
79
90
|
end
|
@@ -81,12 +92,12 @@ module Adhearsion
|
|
81
92
|
protected
|
82
93
|
|
83
94
|
def start_app(path, mode, pid_file = nil)
|
84
|
-
execute_from_app_dir! path
|
85
|
-
say "Starting Adhearsion server at #{
|
95
|
+
execute_from_app_dir! path
|
96
|
+
say "Starting Adhearsion server at #{Dir.pwd}"
|
86
97
|
Adhearsion::Initializer.start :mode => mode, :pid_file => pid_file
|
87
98
|
end
|
88
99
|
|
89
|
-
def execute_from_app_dir!(path
|
100
|
+
def execute_from_app_dir!(path)
|
90
101
|
return if in_app? and running_script_ahn?
|
91
102
|
|
92
103
|
path ||= '.' if in_app?
|
@@ -95,8 +106,8 @@ module Adhearsion
|
|
95
106
|
raise PathInvalid, path unless ScriptAhnLoader.in_ahn_application?(path)
|
96
107
|
|
97
108
|
Dir.chdir path do
|
98
|
-
args.
|
99
|
-
args[1] =
|
109
|
+
args = ARGV.dup
|
110
|
+
args[1] = File.expand_path path
|
100
111
|
ScriptAhnLoader.exec_script_ahn! args
|
101
112
|
end
|
102
113
|
end
|
@@ -138,5 +149,11 @@ module Adhearsion
|
|
138
149
|
super "Directory #{path} does not belong to an Adhearsion project!"
|
139
150
|
end
|
140
151
|
end
|
152
|
+
|
153
|
+
class PIDReadError < Thor::Error
|
154
|
+
def initialize(path)
|
155
|
+
super "Could not read pid from the file #{path}"
|
156
|
+
end
|
157
|
+
end
|
141
158
|
end
|
142
159
|
end
|
@@ -14,22 +14,38 @@ module Adhearsion
|
|
14
14
|
def initialize(&block)
|
15
15
|
initialize_environments
|
16
16
|
|
17
|
+
Loquacious.env_config = true
|
18
|
+
Loquacious.env_prefix = "AHN"
|
19
|
+
|
17
20
|
Loquacious::Configuration.for :platform do
|
18
21
|
root nil, :desc => "Adhearsion application root folder"
|
22
|
+
|
19
23
|
lib "lib", :desc => <<-__
|
20
|
-
Folder to include the own libraries to be used. Adhearsion loads any ruby file
|
21
|
-
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
|
+
want these files to be loaded. This folder is relative to the application root folder.
|
22
27
|
__
|
23
|
-
automatically_accept_incoming_calls true, :desc => "Adhearsion will accept automatically any inbound call"
|
24
28
|
|
25
|
-
|
29
|
+
automatically_accept_incoming_calls true, :transform => Proc.new { |v| v == 'true' }, :desc => <<-__
|
30
|
+
Adhearsion will accept automatically any inbound call
|
31
|
+
__
|
32
|
+
|
33
|
+
environment :development, :transform => Proc.new { |v| v.to_sym }, :desc => <<-__
|
34
|
+
Active environment. Supported values: development, production, staging, test
|
35
|
+
__
|
36
|
+
|
37
|
+
process_name "ahn", :desc => <<-__
|
38
|
+
Adhearsion process name, useful to make it easier to find in the process list
|
39
|
+
Pro tip: set this to your application's name and you can do "killall myapp"
|
40
|
+
Does not work under JRuby.
|
41
|
+
__
|
26
42
|
|
27
43
|
desc "Log configuration"
|
28
44
|
logging {
|
29
|
-
level :info, :desc => <<-__
|
45
|
+
level :info, :transform => Proc.new { |v| v.to_sym }, :desc => <<-__
|
30
46
|
Supported levels (in increasing severity) -- :trace < :debug < :info < :warn < :error < :fatal
|
31
47
|
__
|
32
|
-
outputters ["log/adhearsion.log"], :desc => <<-__
|
48
|
+
outputters ["log/adhearsion.log"], :transform => Proc.new { |val| Array(val) }, :desc => <<-__
|
33
49
|
An array of log outputters to use. The default is to log to stdout and log/adhearsion.log
|
34
50
|
__
|
35
51
|
formatter nil, :desc => <<-__
|
@@ -136,13 +152,26 @@ module Adhearsion
|
|
136
152
|
else
|
137
153
|
return "" if Loquacious::Configuration.for(name).nil?
|
138
154
|
|
155
|
+
if args[:show_values]
|
156
|
+
name_leader = " config.#{name}."
|
157
|
+
desc_leader = " # "
|
158
|
+
name_value_sep = " = "
|
159
|
+
title_leader = " "
|
160
|
+
else
|
161
|
+
name_leader = ""
|
162
|
+
desc_leader = "#"
|
163
|
+
name_value_sep = " => "
|
164
|
+
title_leader = ""
|
165
|
+
end
|
166
|
+
|
139
167
|
config = Loquacious::Configuration.help_for name,
|
140
|
-
:name_leader =>
|
141
|
-
:desc_leader =>
|
168
|
+
:name_leader => name_leader,
|
169
|
+
:desc_leader => desc_leader,
|
142
170
|
:colorize => true,
|
143
|
-
:io => desc
|
171
|
+
:io => desc,
|
172
|
+
:name_value_sep => name_value_sep
|
144
173
|
config.show :values => args[:show_values]
|
145
|
-
"
|
174
|
+
"#{title_leader}# ******* Configuration for #{name} **************\n\n#{desc.string}"
|
146
175
|
end
|
147
176
|
end
|
148
177
|
end
|
data/lib/adhearsion/console.rb
CHANGED
@@ -1,59 +1,78 @@
|
|
1
1
|
require 'pry'
|
2
2
|
|
3
3
|
module Adhearsion
|
4
|
-
|
4
|
+
class Console
|
5
5
|
include Adhearsion
|
6
|
+
include Singleton
|
6
7
|
|
7
8
|
class << self
|
8
9
|
##
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
Pry.prompt = [
|
13
|
-
proc do |*args|
|
14
|
-
obj, nest_level, pry_instance = args
|
15
|
-
"AHN#{' ' * nest_level}> "
|
16
|
-
end,
|
17
|
-
proc do |*args|
|
18
|
-
obj, nest_level, pry_instance = args
|
19
|
-
"AHN#{' ' * nest_level}? "
|
20
|
-
end
|
21
|
-
]
|
22
|
-
Pry.config.command_prefix = "%"
|
23
|
-
if libedit?
|
24
|
-
logger.error "Cannot start. You are running Adhearsion on Ruby with libedit. You must use readline for the console to work."
|
25
|
-
else
|
26
|
-
logger.info "Starting up..."
|
27
|
-
pry
|
28
|
-
end
|
10
|
+
# Include another external functionality into the console
|
11
|
+
def mixin(mod)
|
12
|
+
include mod
|
29
13
|
end
|
30
14
|
|
31
|
-
def
|
32
|
-
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
instance.send method, *args, &block
|
33
17
|
end
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Start the Adhearsion console
|
22
|
+
#
|
23
|
+
def run
|
24
|
+
Pry.prompt = [
|
25
|
+
proc do |*args|
|
26
|
+
obj, nest_level, pry_instance = args
|
27
|
+
"AHN#{' ' * nest_level}> "
|
28
|
+
end,
|
29
|
+
proc do |*args|
|
30
|
+
obj, nest_level, pry_instance = args
|
31
|
+
"AHN#{' ' * nest_level}? "
|
32
|
+
end
|
33
|
+
]
|
34
|
+
Pry.config.command_prefix = "%"
|
35
|
+
if libedit?
|
36
|
+
logger.error "Cannot start. You are running Adhearsion on Ruby with libedit. You must use readline for the console to work."
|
37
|
+
else
|
38
|
+
logger.info "Starting up..."
|
39
|
+
@pry_thread = Thread.current
|
40
|
+
binding.pry
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def stop
|
45
|
+
return unless @pry_thread
|
46
|
+
@pry_thread.kill
|
47
|
+
@pry_thread = nil
|
48
|
+
logger.info "Shutting down"
|
49
|
+
end
|
34
50
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
call = Adhearsion.active_calls[call]
|
39
|
-
end
|
40
|
-
Pry.prompt = [ proc { "AHN<#{call.channel}> " },
|
41
|
-
proc { "AHN<#{call.channel}? " } ]
|
51
|
+
def calls
|
52
|
+
Adhearsion.active_calls
|
53
|
+
end
|
42
54
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
55
|
+
def use(call)
|
56
|
+
unless call.is_a? Adhearsion::Call
|
57
|
+
raise ArgumentError unless Adhearsion.active_calls[call]
|
58
|
+
call = Adhearsion.active_calls[call]
|
47
59
|
end
|
60
|
+
Pry.prompt = [ proc { "AHN<#{call.channel}> " },
|
61
|
+
proc { "AHN<#{call.channel}? " } ]
|
62
|
+
|
63
|
+
# Pause execution of the thread currently controlling the call
|
64
|
+
call.with_command_lock do
|
65
|
+
CallWrapper.new(call).pry
|
66
|
+
end
|
67
|
+
end
|
48
68
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
69
|
+
def libedit?
|
70
|
+
begin
|
71
|
+
# If NotImplemented then this might be libedit
|
72
|
+
Readline.emacs_editing_mode
|
73
|
+
false
|
74
|
+
rescue NotImplementedError
|
75
|
+
true
|
57
76
|
end
|
58
77
|
end
|
59
78
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'adhearsion/linux_proc_name'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module LibC
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib FFI::Library::LIBC
|
7
|
+
|
8
|
+
begin
|
9
|
+
attach_function :prctl, [ :ulong, :ulong, :ulong, :ulong ], :int
|
10
|
+
rescue FFI::NotFoundError => ex
|
11
|
+
Adhearsion::LinuxProcName.error = "Error while attaching libc function prctl: #{ex}"
|
12
|
+
end
|
13
|
+
end
|
@@ -29,9 +29,12 @@ module Adhearsion
|
|
29
29
|
def setup_project
|
30
30
|
self.destination_root = @app_path
|
31
31
|
BASEDIRS.each { |dir| directory dir }
|
32
|
-
|
32
|
+
template "Gemfile.erb", "Gemfile"
|
33
|
+
copy_file "gitignore", ".gitignore"
|
34
|
+
copy_file "Procfile"
|
33
35
|
copy_file "Rakefile"
|
34
36
|
copy_file "README.md"
|
37
|
+
chmod "script/ahn", 0755
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
@@ -1,27 +1,8 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
3
|
require 'rubygems'
|
4
4
|
require 'bundler'
|
5
5
|
Bundler.setup
|
6
6
|
Bundler.require
|
7
7
|
|
8
|
-
|
9
|
-
require 'adhearsion/tasks'
|
10
|
-
rescue LoadError
|
11
|
-
STDERR.puts "\nCannot load Adhearsion! Not all Rake tasks will be loaded!\n\n"
|
12
|
-
end
|
13
|
-
|
14
|
-
desc "Writes a .gitignore file that ignores certain SCM annoyances such as log files"
|
15
|
-
task :gitignore do
|
16
|
-
ignore_file = "#{Dir.pwd}/.gitignore"
|
17
|
-
if File.exists? ignore_file
|
18
|
-
STDERR.puts "File #{ignore_file} already exists!"
|
19
|
-
else
|
20
|
-
File.open ignore_file, 'w' do |file|
|
21
|
-
# Add other files to the Array below
|
22
|
-
%w[ log ].each do |pattern|
|
23
|
-
file.puts pattern
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
8
|
+
require 'adhearsion/tasks'
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'adhearsion/punchblock_plugin'
|
2
|
+
require 'adhearsion/linux_proc_name'
|
2
3
|
|
3
4
|
module Adhearsion
|
4
5
|
class Initializer
|
@@ -38,14 +39,14 @@ module Adhearsion
|
|
38
39
|
def start
|
39
40
|
resolve_pid_file_path
|
40
41
|
load_lib_folder
|
41
|
-
load_plugins_methods
|
42
42
|
load_config
|
43
43
|
initialize_log_paths
|
44
44
|
daemonize! if should_daemonize?
|
45
|
+
start_logging
|
45
46
|
launch_console if need_console?
|
46
47
|
catch_termination_signal
|
47
48
|
create_pid_file
|
48
|
-
|
49
|
+
set_ahn_proc_name
|
49
50
|
logger.info "Loaded config in <#{Adhearsion.config.platform.environment}> environment"
|
50
51
|
initialize_exception_logger
|
51
52
|
update_rails_env_var
|
@@ -54,7 +55,11 @@ module Adhearsion
|
|
54
55
|
logger.info "Adhearsion v#{Adhearsion::VERSION} initialized!"
|
55
56
|
Adhearsion::Process.booted
|
56
57
|
|
58
|
+
run_plugins
|
57
59
|
trigger_after_initialized_hooks
|
60
|
+
|
61
|
+
# This method will block until all important threads have finished.
|
62
|
+
# When it does, the process will exit.
|
58
63
|
join_important_threads
|
59
64
|
self
|
60
65
|
end
|
@@ -62,20 +67,20 @@ module Adhearsion
|
|
62
67
|
def update_rails_env_var
|
63
68
|
env = ENV['AHN_ENV']
|
64
69
|
if env && Adhearsion.config.valid_environment?(env.to_sym)
|
65
|
-
if ENV['RAILS_ENV']
|
70
|
+
if ENV['RAILS_ENV'] == env
|
71
|
+
logger.info "Using the configured value for RAILS_ENV : <#{env}>"
|
72
|
+
else
|
66
73
|
logger.warn "Updating AHN_RAILS variable to <#{env}>"
|
67
74
|
ENV['RAILS_ENV'] = env
|
68
|
-
else
|
69
|
-
logger.info "Using the configured value for RAILS_ENV : <#{env}>"
|
70
75
|
end
|
71
76
|
else
|
72
77
|
env = ENV['RAILS_ENV']
|
73
|
-
|
78
|
+
if env
|
79
|
+
logger.info "Using the configured value for RAILS_ENV : <#{env}>"
|
80
|
+
else
|
74
81
|
env = Adhearsion.config.platform.environment.to_s
|
75
82
|
logger.info "Defining AHN_RAILS variable to <#{env}>"
|
76
83
|
ENV['RAILS_ENV'] = env
|
77
|
-
else
|
78
|
-
logger.info "Using the configured value for RAILS_ENV : <#{env}>"
|
79
84
|
end
|
80
85
|
end
|
81
86
|
env
|
@@ -107,15 +112,18 @@ module Adhearsion
|
|
107
112
|
def catch_termination_signal
|
108
113
|
%w'INT TERM'.each do |process_signal|
|
109
114
|
trap process_signal do
|
115
|
+
logger.info "Received #{process_signal} signal. Shutting down."
|
110
116
|
Adhearsion::Process.shutdown
|
111
117
|
end
|
112
118
|
end
|
113
119
|
|
114
120
|
trap 'QUIT' do
|
121
|
+
logger.info "Received QUIT signal. Hard shutting down."
|
115
122
|
Adhearsion::Process.hard_shutdown
|
116
123
|
end
|
117
124
|
|
118
125
|
trap 'ABRT' do
|
126
|
+
logger.info "Received ABRT signal. Forcing stop."
|
119
127
|
Adhearsion::Process.force_stop
|
120
128
|
end
|
121
129
|
end
|
@@ -177,14 +185,14 @@ module Adhearsion
|
|
177
185
|
end
|
178
186
|
end
|
179
187
|
|
180
|
-
def load_plugins_methods
|
181
|
-
Plugin.load_methods
|
182
|
-
end
|
183
|
-
|
184
188
|
def init_plugins
|
185
189
|
Plugin.init_plugins
|
186
190
|
end
|
187
191
|
|
192
|
+
def run_plugins
|
193
|
+
Plugin.run_plugins
|
194
|
+
end
|
195
|
+
|
188
196
|
def should_daemonize?
|
189
197
|
@mode == :daemon
|
190
198
|
end
|
@@ -251,6 +259,10 @@ module Adhearsion
|
|
251
259
|
end
|
252
260
|
end
|
253
261
|
|
262
|
+
def set_ahn_proc_name
|
263
|
+
Adhearsion::LinuxProcName.set_proc_name Adhearsion.config.platform.process_name
|
264
|
+
end
|
265
|
+
|
254
266
|
def trigger_after_initialized_hooks
|
255
267
|
Events.trigger_immediately :after_initialized
|
256
268
|
end
|