adhearsion 2.0.0.alpha1 → 2.0.0.alpha2
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 +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
|