adhearsion 2.0.0.beta1 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -4
- data/CHANGELOG.md +34 -4
- data/README.markdown +2 -1
- data/Rakefile +22 -1
- data/adhearsion.gemspec +1 -0
- data/bin/ahn +0 -2
- data/features/cli_daemon.feature +2 -0
- data/features/cli_restart.feature +19 -0
- data/features/cli_start.feature +4 -6
- data/features/cli_stop.feature +3 -0
- data/features/step_definitions/app_generator_steps.rb +2 -0
- data/features/step_definitions/cli_steps.rb +2 -0
- data/features/support/aruba_helper.rb +2 -0
- data/features/support/env.rb +8 -46
- data/features/support/utils.rb +2 -0
- data/lib/adhearsion.rb +4 -6
- data/lib/adhearsion/call.rb +71 -17
- data/lib/adhearsion/call_controller.rb +25 -14
- data/lib/adhearsion/call_controller/dial.rb +34 -15
- data/lib/adhearsion/call_controller/input.rb +186 -144
- data/lib/adhearsion/call_controller/output.rb +10 -6
- data/lib/adhearsion/call_controller/record.rb +11 -13
- data/lib/adhearsion/call_controller/utility.rb +2 -0
- data/lib/adhearsion/calls.rb +4 -2
- data/lib/adhearsion/cli.rb +4 -0
- data/lib/adhearsion/cli_commands.rb +8 -2
- data/lib/adhearsion/configuration.rb +7 -3
- data/lib/adhearsion/console.rb +17 -17
- data/lib/adhearsion/events.rb +10 -4
- data/lib/adhearsion/foundation.rb +9 -0
- data/lib/adhearsion/foundation/custom_daemonizer.rb +3 -1
- data/lib/adhearsion/foundation/exception_handler.rb +2 -0
- data/lib/adhearsion/foundation/libc.rb +2 -0
- data/lib/adhearsion/foundation/object.rb +3 -0
- data/lib/adhearsion/foundation/thread_safety.rb +5 -11
- data/lib/adhearsion/generators.rb +2 -0
- data/lib/adhearsion/generators/app/app_generator.rb +2 -0
- data/lib/adhearsion/generators/app/templates/README.md +9 -0
- data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +38 -16
- data/lib/adhearsion/generators/app/templates/config/environment.rb +2 -0
- data/lib/adhearsion/generators/app/templates/lib/simon_game.rb +5 -3
- data/lib/adhearsion/generators/controller/controller_generator.rb +2 -0
- data/lib/adhearsion/generators/controller/templates/lib/controller.rb +2 -0
- data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +2 -0
- data/lib/adhearsion/generators/generator.rb +3 -1
- data/lib/adhearsion/generators/plugin/plugin_generator.rb +2 -0
- data/lib/adhearsion/initializer.rb +31 -17
- data/lib/adhearsion/linux_proc_name.rb +2 -0
- data/lib/adhearsion/logging.rb +5 -3
- data/lib/adhearsion/menu_dsl.rb +2 -0
- data/lib/adhearsion/menu_dsl/calculated_match.rb +2 -0
- data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +2 -0
- data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +2 -0
- data/lib/adhearsion/menu_dsl/match_calculator.rb +2 -0
- data/lib/adhearsion/menu_dsl/menu.rb +58 -4
- data/lib/adhearsion/menu_dsl/menu_builder.rb +14 -1
- data/lib/adhearsion/menu_dsl/range_match_calculator.rb +4 -1
- data/lib/adhearsion/menu_dsl/string_match_calculator.rb +2 -0
- data/lib/adhearsion/outbound_call.rb +2 -0
- data/lib/adhearsion/plugin.rb +9 -7
- data/lib/adhearsion/plugin/collection.rb +3 -1
- data/lib/adhearsion/plugin/initializer.rb +3 -1
- data/lib/adhearsion/process.rb +8 -2
- data/lib/adhearsion/punchblock_plugin.rb +3 -1
- data/lib/adhearsion/punchblock_plugin/initializer.rb +34 -11
- data/lib/adhearsion/router.rb +4 -2
- data/lib/adhearsion/router/route.rb +2 -0
- data/lib/adhearsion/script_ahn_loader.rb +2 -0
- data/lib/adhearsion/tasks.rb +2 -0
- data/lib/adhearsion/tasks/configuration.rb +2 -0
- data/lib/adhearsion/tasks/debugging.rb +8 -0
- data/lib/adhearsion/tasks/environment.rb +2 -0
- data/lib/adhearsion/tasks/plugins.rb +2 -0
- data/lib/adhearsion/tasks/testing.rb +2 -0
- data/lib/adhearsion/version.rb +3 -1
- data/pre-commit +2 -0
- data/spec/adhearsion/call_controller/dial_spec.rb +114 -25
- data/spec/adhearsion/call_controller/input_spec.rb +192 -169
- data/spec/adhearsion/call_controller/output_spec.rb +26 -12
- data/spec/adhearsion/call_controller/record_spec.rb +29 -77
- data/spec/adhearsion/call_controller/utility_spec.rb +69 -0
- data/spec/adhearsion/call_controller_spec.rb +90 -15
- data/spec/adhearsion/call_spec.rb +92 -24
- data/spec/adhearsion/calls_spec.rb +9 -7
- data/spec/adhearsion/configuration_spec.rb +58 -56
- data/spec/adhearsion/console_spec.rb +4 -2
- data/spec/adhearsion/events_spec.rb +9 -7
- data/spec/adhearsion/generators_spec.rb +3 -1
- data/spec/adhearsion/initializer_spec.rb +16 -14
- data/spec/adhearsion/logging_spec.rb +11 -9
- data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +6 -4
- data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +6 -4
- data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +3 -1
- data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +2 -0
- data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +42 -11
- data/spec/adhearsion/menu_dsl/menu_spec.rb +197 -36
- data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +4 -2
- data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +5 -3
- data/spec/adhearsion/outbound_call_spec.rb +7 -5
- data/spec/adhearsion/plugin_spec.rb +19 -15
- data/spec/adhearsion/process_spec.rb +12 -7
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +35 -15
- data/spec/adhearsion/punchblock_plugin_spec.rb +4 -1
- data/spec/adhearsion/router/route_spec.rb +8 -6
- data/spec/adhearsion/router_spec.rb +12 -10
- data/spec/adhearsion_spec.rb +13 -2
- data/spec/capture_warnings.rb +33 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/call_controller_test_helpers.rb +2 -4
- data/spec/support/initializer_stubs.rb +8 -5
- data/spec/support/logging_helpers.rb +2 -0
- data/spec/support/punchblock_mocks.rb +2 -0
- metadata +84 -71
- data/EVENTS +0 -11
- data/lib/adhearsion/call_controller/menu.rb +0 -124
- data/lib/adhearsion/foundation/all.rb +0 -8
- data/spec/adhearsion/call_controller/menu_spec.rb +0 -120
- data/spec/adhearsion/menu_dsl_spec.rb +0 -12
@@ -1,9 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Adhearsion
|
2
4
|
class CallController
|
3
5
|
module Output
|
4
|
-
|
6
|
+
PlaybackError = Class.new StandardError # Represents failure to play audio, such as when the sound file cannot be found
|
7
|
+
|
8
|
+
def say(text, options = {})
|
5
9
|
play_ssml(text, options) || output(:text, text.to_s, options)
|
6
10
|
end
|
11
|
+
alias :speak :say
|
7
12
|
|
8
13
|
#
|
9
14
|
# Plays the specified sound file names. This method will handle Time/DateTime objects (e.g. Time.now),
|
@@ -50,7 +55,7 @@ module Adhearsion
|
|
50
55
|
# @see play
|
51
56
|
#
|
52
57
|
def play!(*arguments)
|
53
|
-
play
|
58
|
+
play(*arguments) or raise PlaybackError, "One of the passed outputs is invalid"
|
54
59
|
end
|
55
60
|
|
56
61
|
#
|
@@ -162,7 +167,7 @@ module Adhearsion
|
|
162
167
|
result = interruptible_play! output
|
163
168
|
rescue PlaybackError => e
|
164
169
|
# Ignore this exception and play the next output
|
165
|
-
logger.warn e.message
|
170
|
+
logger.warn "Error playing back the prompt: #{e.message}"
|
166
171
|
ensure
|
167
172
|
break if result
|
168
173
|
end
|
@@ -174,7 +179,7 @@ module Adhearsion
|
|
174
179
|
result = nil
|
175
180
|
result = :time if [Date, Time, DateTime].include? output.class
|
176
181
|
result = :numeric if output.kind_of?(Numeric) || output =~ /^\d+$/
|
177
|
-
result = :audio if !result && (
|
182
|
+
result = :audio if !result && (/^\//.match(output.to_s) || URI::regexp.match(output.to_s))
|
178
183
|
result ||= :text
|
179
184
|
end
|
180
185
|
|
@@ -247,13 +252,12 @@ module Adhearsion
|
|
247
252
|
:value => grammar_accept(digits).to_s
|
248
253
|
}
|
249
254
|
input_stopper_component.register_event_handler ::Punchblock::Event::Complete do |event|
|
250
|
-
logger.warn "#stream_file Handling input complete event."
|
251
255
|
output_component.stop! unless output_component.complete?
|
252
256
|
end
|
253
257
|
write_and_await_response input_stopper_component
|
254
258
|
begin
|
255
259
|
execute_component_and_await_completion output_component
|
256
|
-
rescue StandardError
|
260
|
+
rescue StandardError
|
257
261
|
raise Adhearsion::PlaybackError, "Output failed for argument #{argument.inspect}"
|
258
262
|
end
|
259
263
|
input_stopper_component.stop! if input_stopper_component.executing?
|
@@ -1,13 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Adhearsion
|
2
4
|
class CallController
|
3
5
|
module Record
|
6
|
+
RecordError = Class.new StandardError # Represents failure to record such as when a file cannot be written.
|
7
|
+
|
4
8
|
#
|
5
9
|
# Start a recording
|
6
10
|
#
|
7
11
|
# @param [Hash] options
|
8
12
|
# @param [Block] &block to process result of the record method
|
9
13
|
# @option options [Boolean, Optional] :async Execute asynchronously. Defaults to false
|
10
|
-
# @option options [Proc, Optional] :on_complete Block to be executed on completion when this method is invoked asynchronously
|
11
14
|
# @option options [Boolean, Optional] :start_beep Indicates whether subsequent record will be preceded with a beep. Default is true.
|
12
15
|
# @option options [Boolean, Optional] :start_paused Whether subsequent record will start in PAUSE mode. Default is false.
|
13
16
|
# @option options [String, Optional] :max_duration Indicates the maximum duration (milliseconds) for a recording.
|
@@ -18,23 +21,18 @@ module Adhearsion
|
|
18
21
|
#
|
19
22
|
# @return recording object
|
20
23
|
|
21
|
-
def record(options = {}
|
22
|
-
async = options.delete
|
23
|
-
on_complete = options.delete :on_complete
|
24
|
+
def record(options = {})
|
25
|
+
async = options.delete :async
|
24
26
|
|
25
27
|
component = ::Punchblock::Component::Record.new options
|
28
|
+
component.register_event_handler ::Punchblock::Event::Complete do |event|
|
29
|
+
catching_standard_errors { yield event if block_given? }
|
30
|
+
end
|
26
31
|
|
27
32
|
if async
|
28
|
-
|
29
|
-
# FIXME: Setting the callback after we begin execution constitutes a race condition. We need to mock the component creation here, since the tests assume we're using whatever is returned by component exection, and that's what we pass the complete event to
|
30
|
-
result.register_event_handler Punchblock::Event::Complete do |event|
|
31
|
-
catching_standard_errors { on_complete.call event }
|
32
|
-
end
|
33
|
-
end
|
33
|
+
write_and_await_response component
|
34
34
|
else
|
35
|
-
execute_component_and_await_completion
|
36
|
-
yield result.complete_event if block_given?
|
37
|
-
end
|
35
|
+
execute_component_and_await_completion component
|
38
36
|
end
|
39
37
|
end
|
40
38
|
end
|
data/lib/adhearsion/calls.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'thread'
|
2
4
|
|
3
5
|
module Adhearsion
|
@@ -44,14 +46,14 @@ module Adhearsion
|
|
44
46
|
|
45
47
|
def with_tag(tag)
|
46
48
|
atomically do
|
47
|
-
calls.inject([]) do |calls_with_tag,(
|
49
|
+
calls.inject([]) do |calls_with_tag,(_,call)|
|
48
50
|
call.tagged_with?(tag) ? calls_with_tag << call : calls_with_tag
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
def each(&block)
|
54
|
-
atomically { calls.values.each
|
56
|
+
atomically { calls.values.each(&block) }
|
55
57
|
end
|
56
58
|
|
57
59
|
def each_pair
|
data/lib/adhearsion/cli.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'adhearsion/script_ahn_loader'
|
2
4
|
|
3
5
|
# If we are inside an Adhearsion application this method performs an exec and thus
|
4
6
|
# the rest of this script is not run.
|
5
7
|
Adhearsion::ScriptAhnLoader.exec_script_ahn!
|
6
8
|
|
9
|
+
require 'bundler/setup'
|
10
|
+
require 'adhearsion'
|
7
11
|
require 'adhearsion/cli_commands'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
require 'adhearsion/script_ahn_loader'
|
3
5
|
require 'thor'
|
@@ -95,14 +97,18 @@ module Adhearsion
|
|
95
97
|
rescue Errno::ESRCH
|
96
98
|
end
|
97
99
|
|
98
|
-
File.delete pid_file
|
100
|
+
File.delete pid_file if File.exists? pid_file
|
99
101
|
end
|
100
102
|
|
101
103
|
desc "restart </path/to/directory>", "Restart the Adhearsion server"
|
102
104
|
method_option :pidfile, :type => :string, :aliases => %w(--pid-file)
|
103
105
|
def restart(path = nil)
|
104
106
|
execute_from_app_dir! path
|
105
|
-
|
107
|
+
begin
|
108
|
+
invoke :stop
|
109
|
+
rescue PIDReadError => e
|
110
|
+
puts e.message
|
111
|
+
end
|
106
112
|
invoke :daemon
|
107
113
|
end
|
108
114
|
|
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
|
+
module Adhearsion
|
3
4
|
class Configuration
|
4
5
|
|
6
|
+
ConfigurationError = Class.new StandardError # Error raised while trying to configure a non existent plugin
|
7
|
+
|
5
8
|
##
|
6
9
|
# Initialize the configuration object
|
7
10
|
#
|
@@ -72,9 +75,10 @@ module Adhearsion
|
|
72
75
|
end
|
73
76
|
|
74
77
|
def add_environment(env)
|
78
|
+
return if self.class.method_defined? env.to_sym
|
75
79
|
self.class.send(:define_method, env.to_sym) do |*args, &block|
|
76
80
|
unless block.nil? || env != self.platform.environment.to_sym
|
77
|
-
self.instance_eval
|
81
|
+
self.instance_eval(&block)
|
78
82
|
end
|
79
83
|
self
|
80
84
|
end
|
@@ -96,7 +100,7 @@ module Adhearsion
|
|
96
100
|
# Adhearsion.config.foo => returns the configuration object associated to the foo plugin
|
97
101
|
def method_missing(method_name, *args, &block)
|
98
102
|
config = Loquacious::Configuration.for method_name, &block
|
99
|
-
raise Adhearsion::ConfigurationError.new "Invalid plugin #{method_name}" if config.nil?
|
103
|
+
raise Adhearsion::Configuration::ConfigurationError.new "Invalid plugin #{method_name}" if config.nil?
|
100
104
|
config
|
101
105
|
end
|
102
106
|
|
data/lib/adhearsion/console.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'pry'
|
2
4
|
|
3
5
|
module Adhearsion
|
@@ -33,18 +35,18 @@ module Adhearsion
|
|
33
35
|
if libedit?
|
34
36
|
logger.error "Cannot start. You are running Adhearsion on Ruby with libedit. You must use readline for the console to work."
|
35
37
|
else
|
36
|
-
logger.info "
|
38
|
+
logger.info "Launching Adhearsion Console"
|
37
39
|
@pry_thread = Thread.current
|
38
40
|
pry
|
39
|
-
logger.info "Console exiting"
|
41
|
+
logger.info "Adhearsion Console exiting"
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
43
45
|
def stop
|
44
|
-
return unless
|
46
|
+
return unless instance_variable_defined?(:@pry_thread)
|
45
47
|
@pry_thread.kill
|
46
48
|
@pry_thread = nil
|
47
|
-
logger.info "
|
49
|
+
logger.info "Adhearsion Console shutting down"
|
48
50
|
end
|
49
51
|
|
50
52
|
def log_level(level = nil)
|
@@ -76,15 +78,17 @@ module Adhearsion
|
|
76
78
|
when nil
|
77
79
|
case calls.size
|
78
80
|
when 0
|
79
|
-
logger.warn "No calls
|
81
|
+
logger.warn "No calls active to take"
|
80
82
|
when 1
|
81
83
|
interact_with_call calls.values.first
|
82
84
|
else
|
83
85
|
puts "Please choose a call:"
|
86
|
+
puts "# (inbound/outbound) details"
|
84
87
|
current_calls = calls.values
|
85
|
-
current_calls.each_with_index do |
|
86
|
-
puts "#{index}
|
88
|
+
current_calls.each_with_index do |active_call, index|
|
89
|
+
puts "#{index}: (#{active_call.is_a?(OutboundCall) ? 'o' : 'i' }) #{active_call.id} from #{active_call.from} to #{active_call.to}"
|
87
90
|
end
|
91
|
+
print "#> "
|
88
92
|
index = input.gets.chomp.to_i
|
89
93
|
call = current_calls[index]
|
90
94
|
interact_with_call call
|
@@ -112,11 +116,11 @@ module Adhearsion
|
|
112
116
|
def set_prompt
|
113
117
|
Pry.prompt = [
|
114
118
|
proc do |*args|
|
115
|
-
|
119
|
+
_, nest_level, _ = args
|
116
120
|
"AHN#{' ' * nest_level}> "
|
117
121
|
end,
|
118
122
|
proc do |*args|
|
119
|
-
|
123
|
+
_, nest_level, _ = args
|
120
124
|
"AHN#{' ' * nest_level}? "
|
121
125
|
end
|
122
126
|
]
|
@@ -130,20 +134,16 @@ module Adhearsion
|
|
130
134
|
call.pause_controllers
|
131
135
|
CallController.exec InteractiveController.new(call)
|
132
136
|
ensure
|
133
|
-
logger.debug "
|
137
|
+
logger.debug "Restoring control of call to controllers"
|
134
138
|
call.resume_controllers
|
135
139
|
end
|
136
140
|
end
|
137
141
|
|
138
142
|
class InteractiveController < CallController
|
139
143
|
def run
|
140
|
-
logger.debug "Starting interactive controller
|
141
|
-
|
142
|
-
|
143
|
-
rescue => e
|
144
|
-
logger.error e
|
145
|
-
end
|
146
|
-
logger.debug "Interactive controller finished."
|
144
|
+
logger.debug "Starting interactive controller"
|
145
|
+
pry
|
146
|
+
logger.debug "Interactive controller finished"
|
147
147
|
end
|
148
148
|
|
149
149
|
def hangup(*args)
|
data/lib/adhearsion/events.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Adhearsion
|
2
4
|
class Events
|
3
5
|
|
@@ -26,7 +28,7 @@ module Adhearsion
|
|
26
28
|
refresh!
|
27
29
|
|
28
30
|
def queue
|
29
|
-
@queue
|
31
|
+
queue? ? @queue : reinitialize_queue!
|
30
32
|
end
|
31
33
|
|
32
34
|
def trigger(type, object = nil)
|
@@ -37,8 +39,12 @@ module Adhearsion
|
|
37
39
|
queue.push_immediately Message.new(type, object)
|
38
40
|
end
|
39
41
|
|
42
|
+
def queue?
|
43
|
+
instance_variable_defined? :@queue
|
44
|
+
end
|
45
|
+
|
40
46
|
def reinitialize_queue!
|
41
|
-
GirlFriday.shutdown! if
|
47
|
+
GirlFriday.shutdown! if queue?
|
42
48
|
# TODO: Extract number of threads to use from Adhearsion.config
|
43
49
|
@queue = GirlFriday::WorkQueue.new 'main_queue', :error_handler => ErrorHandler do |message|
|
44
50
|
begin
|
@@ -54,7 +60,7 @@ module Adhearsion
|
|
54
60
|
end
|
55
61
|
|
56
62
|
def draw(&block)
|
57
|
-
instance_exec
|
63
|
+
instance_exec(&block)
|
58
64
|
end
|
59
65
|
|
60
66
|
def method_missing(method_name, *args, &block)
|
@@ -62,7 +68,7 @@ module Adhearsion
|
|
62
68
|
end
|
63
69
|
|
64
70
|
def respond_to?(method_name)
|
65
|
-
return true if
|
71
|
+
return true if instance_variable_defined?(:@handlers) && @handlers.has_key?(method_name)
|
66
72
|
super
|
67
73
|
end
|
68
74
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
# This is largely based on the Daemonize library by Travis Whitton and
|
2
4
|
# Judson Lester. http://grub.ath.cx/daemonize. I cleaned it up a bit to
|
3
5
|
# meet Adhearsion's quality standards.
|
@@ -28,7 +30,7 @@ module Adhearsion
|
|
28
30
|
# Prevent the possibility of acquiring a controlling terminal
|
29
31
|
if oldmode.zero?
|
30
32
|
trap 'SIGHUP', 'IGNORE'
|
31
|
-
exit if
|
33
|
+
exit if safefork
|
32
34
|
end
|
33
35
|
|
34
36
|
Dir.chdir "/" # Release old working directory
|
@@ -1,15 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'thread'
|
2
4
|
|
3
5
|
class Object
|
4
6
|
def synchronize(&block)
|
5
7
|
@mutex ||= Mutex.new
|
6
|
-
@mutex.synchronize
|
8
|
+
@mutex.synchronize(&block)
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
|
-
class ThreadSafeArray
|
12
|
+
class ThreadSafeArray < BasicObject
|
11
13
|
def initialize
|
12
|
-
@mutex = Mutex.new
|
14
|
+
@mutex = ::Mutex.new
|
13
15
|
@array = []
|
14
16
|
end
|
15
17
|
|
@@ -18,12 +20,4 @@ class ThreadSafeArray
|
|
18
20
|
@array.send method, *args, &block
|
19
21
|
end
|
20
22
|
end
|
21
|
-
|
22
|
-
def inspect
|
23
|
-
@mutex.synchronize { @array.inspect }
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_s
|
27
|
-
@mutex.synchronize { @array.to_s }
|
28
|
-
end
|
29
23
|
end
|
@@ -25,4 +25,13 @@ In `config/adhearsion.rb` you'll need to set the VoIP platform you're using, alo
|
|
25
25
|
|
26
26
|
Start your new app with "ahn start /path/to/your/app". You'll get a lovely console and should be presented with the SimonGame
|
27
27
|
|
28
|
+
### Running your app on heroku
|
29
|
+
|
30
|
+
In order to run an adhearsion application on Heroku, you must create the application on the 'cedar' stack (`heroku apps:create --stack cedar`) and re-scale your processes like so:
|
31
|
+
|
32
|
+
```
|
33
|
+
heroku ps:scale web=0
|
34
|
+
heroku ps:scale ahn=1
|
35
|
+
```
|
36
|
+
|
28
37
|
Check out [the Adhearsion website](http://adhearsion.com) for more details of where to go from here.
|