eric-adhearsion 0.7.999 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -2
- data/EVENTS +11 -0
- data/Rakefile +96 -24
- data/adhearsion.gemspec +148 -0
- data/app_generators/ahn/ahn_generator.rb +24 -9
- data/app_generators/ahn/templates/.ahnrc +25 -3
- data/app_generators/ahn/templates/Rakefile +22 -2
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
- data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/config.yml +12 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
- data/app_generators/ahn/templates/components/simon_game/{lib/simon_game.rb → simon_game.rb} +14 -19
- data/app_generators/ahn/templates/config/startup.rb +3 -6
- data/app_generators/ahn/templates/dialplan.rb +2 -3
- data/app_generators/ahn/templates/events.rb +32 -0
- data/bin/jahn +10 -0
- data/examples/asterisk_manager_interface/standalone.rb +51 -0
- data/lib/adhearsion.rb +17 -11
- data/lib/adhearsion/cli.rb +141 -24
- data/lib/adhearsion/component_manager.rb +169 -238
- data/lib/adhearsion/component_manager/component_tester.rb +55 -0
- data/lib/adhearsion/component_manager/spec_framework.rb +24 -0
- data/lib/adhearsion/events_support.rb +84 -0
- data/lib/adhearsion/{core_extensions → foundation}/all.rb +0 -0
- data/lib/adhearsion/{blank_slate.rb → foundation/blank_slate.rb} +0 -0
- data/lib/adhearsion/{core_extensions → foundation}/custom_daemonizer.rb +0 -0
- data/lib/adhearsion/foundation/event_socket.rb +203 -0
- data/lib/adhearsion/foundation/future_resource.rb +36 -0
- data/lib/adhearsion/{core_extensions → foundation}/global.rb +0 -0
- data/lib/adhearsion/{core_extensions → foundation}/metaprogramming.rb +0 -0
- data/lib/adhearsion/foundation/numeric.rb +13 -0
- data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
- data/lib/adhearsion/{core_extensions → foundation}/relationship_properties.rb +2 -0
- data/lib/adhearsion/foundation/string.rb +26 -0
- data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
- data/lib/adhearsion/{core_extensions → foundation}/thread_safety.rb +0 -0
- data/lib/adhearsion/host_definitions.rb +5 -1
- data/lib/adhearsion/initializer.rb +229 -73
- data/lib/adhearsion/initializer/asterisk.rb +33 -11
- data/lib/adhearsion/initializer/configuration.rb +58 -6
- data/lib/adhearsion/initializer/database.rb +3 -46
- data/lib/adhearsion/initializer/drb.rb +9 -3
- data/lib/adhearsion/initializer/freeswitch.rb +3 -3
- data/lib/adhearsion/initializer/rails.rb +1 -1
- data/lib/adhearsion/tasks.rb +2 -1
- data/lib/adhearsion/tasks/deprecations.rb +59 -0
- data/lib/adhearsion/version.rb +3 -3
- data/lib/adhearsion/voip/asterisk.rb +2 -2
- data/lib/adhearsion/voip/asterisk/agi_server.rb +9 -6
- data/lib/adhearsion/voip/asterisk/commands.rb +106 -4
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +562 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1754 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +286 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
- data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
- data/lib/adhearsion/voip/call.rb +51 -2
- data/lib/adhearsion/voip/dial_plan.rb +74 -61
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -6
- data/lib/adhearsion/voip/dsl/numerical_string.rb +2 -2
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +2 -2
- data/lib/theatre.rb +151 -0
- data/lib/theatre/README.markdown +64 -0
- data/lib/theatre/callback_definition_loader.rb +84 -0
- data/lib/theatre/guid.rb +23 -0
- data/lib/theatre/invocation.rb +121 -0
- data/lib/theatre/namespace_manager.rb +153 -0
- data/lib/theatre/version.rb +2 -0
- metadata +63 -138
- data/Manifest.txt +0 -149
- data/README.txt +0 -6
- data/ahn_generators/component/USAGE +0 -5
- data/ahn_generators/component/component_generator.rb +0 -57
- data/ahn_generators/component/templates/configuration.rb +0 -0
- data/ahn_generators/component/templates/lib/lib.rb.erb +0 -3
- data/ahn_generators/component/templates/test/test.rb.erb +0 -12
- data/ahn_generators/component/templates/test/test_helper.rb +0 -14
- data/app_generators/ahn/templates/components/simon_game/configuration.rb +0 -0
- data/app_generators/ahn/templates/components/simon_game/test/test_helper.rb +0 -14
- data/app_generators/ahn/templates/components/simon_game/test/test_simon_game.rb +0 -31
- data/lib/adhearsion/core_extensions/array.rb +0 -0
- data/lib/adhearsion/core_extensions/guid.rb +0 -5
- data/lib/adhearsion/core_extensions/hash.rb +0 -0
- data/lib/adhearsion/core_extensions/numeric.rb +0 -4
- data/lib/adhearsion/core_extensions/proc.rb +0 -0
- data/lib/adhearsion/core_extensions/pseudo_uuid.rb +0 -11
- data/lib/adhearsion/core_extensions/publishable.rb +0 -73
- data/lib/adhearsion/core_extensions/string.rb +0 -26
- data/lib/adhearsion/core_extensions/thread.rb +0 -13
- data/lib/adhearsion/core_extensions/time.rb +0 -0
- data/lib/adhearsion/distributed/gateways/dbus_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/osa_gateway.rb +0 -0
- data/lib/adhearsion/distributed/gateways/rest_gateway.rb +0 -9
- data/lib/adhearsion/distributed/gateways/soap_gateway.rb +0 -9
- data/lib/adhearsion/distributed/gateways/xmlrpc_gateway.rb +0 -9
- data/lib/adhearsion/distributed/peer_finder.rb +0 -0
- data/lib/adhearsion/distributed/remote_cli.rb +0 -0
- data/lib/adhearsion/hooks.rb +0 -57
- data/lib/adhearsion/initializer/paths.rb +0 -55
- data/lib/adhearsion/services/scheduler.rb +0 -5
- data/lib/adhearsion/voip/asterisk/ami.rb +0 -147
- data/lib/adhearsion/voip/asterisk/ami/actions.rb +0 -238
- data/lib/adhearsion/voip/asterisk/ami/machine.rb +0 -871
- data/lib/adhearsion/voip/asterisk/ami/machine.rl +0 -109
- data/lib/adhearsion/voip/asterisk/ami/parser.rb +0 -262
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/spec/fixtures/dialplan.rb +0 -3
- data/spec/initializer/test_configuration.rb +0 -267
- data/spec/initializer/test_loading.rb +0 -162
- data/spec/initializer/test_paths.rb +0 -43
- data/spec/silence.rb +0 -10
- data/spec/test_ahn_command.rb +0 -149
- data/spec/test_code_quality.rb +0 -87
- data/spec/test_component_manager.rb +0 -97
- data/spec/test_constants.rb +0 -8
- data/spec/test_drb.rb +0 -104
- data/spec/test_helper.rb +0 -94
- data/spec/test_hooks.rb +0 -37
- data/spec/test_host_definitions.rb +0 -79
- data/spec/test_initialization.rb +0 -105
- data/spec/test_logging.rb +0 -80
- data/spec/test_relationship_properties.rb +0 -54
- data/spec/voip/asterisk/ami_response_definitions.rb +0 -23
- data/spec/voip/asterisk/config_file_generators/test_agents.rb +0 -253
- data/spec/voip/asterisk/config_file_generators/test_queues.rb +0 -325
- data/spec/voip/asterisk/config_file_generators/test_voicemail.rb +0 -306
- data/spec/voip/asterisk/menu_command/test_calculated_match.rb +0 -111
- data/spec/voip/asterisk/menu_command/test_matchers.rb +0 -98
- data/spec/voip/asterisk/mock_ami_server.rb +0 -176
- data/spec/voip/asterisk/test_agi_server.rb +0 -451
- data/spec/voip/asterisk/test_ami.rb +0 -227
- data/spec/voip/asterisk/test_commands.rb +0 -2006
- data/spec/voip/asterisk/test_config_manager.rb +0 -129
- data/spec/voip/dsl/dispatcher_spec_helper.rb +0 -45
- data/spec/voip/dsl/test_dialing_dsl.rb +0 -268
- data/spec/voip/dsl/test_dispatcher.rb +0 -82
- data/spec/voip/dsl/test_parser.rb +0 -87
- data/spec/voip/freeswitch/test_basic_connection_manager.rb +0 -39
- data/spec/voip/freeswitch/test_inbound_connection_manager.rb +0 -39
- data/spec/voip/freeswitch/test_oes_server.rb +0 -9
- data/spec/voip/test_call_routing.rb +0 -127
- data/spec/voip/test_dialplan_manager.rb +0 -372
- data/spec/voip/test_numerical_string.rb +0 -48
- data/spec/voip/test_phone_number.rb +0 -36
- data/test/test_ahn_generator.rb +0 -59
- data/test/test_component_generator.rb +0 -52
- data/test/test_generator_helper.rb +0 -20
@@ -0,0 +1,19 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
module VoIP
|
3
|
+
module Asterisk
|
4
|
+
module Manager
|
5
|
+
|
6
|
+
##
|
7
|
+
# Higher level abstraction of the Asterisk Manager Interface.
|
8
|
+
#
|
9
|
+
class SuperManager
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/adhearsion/voip/call.rb
CHANGED
@@ -61,6 +61,18 @@ module Adhearsion
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
def with_tag(tag)
|
65
|
+
atomically do
|
66
|
+
calls.inject(Array.new) do |calls_with_tag,(key,call)|
|
67
|
+
call.tagged_with?(tag) ? calls_with_tag << call : calls_with_tag
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_a
|
73
|
+
calls.values
|
74
|
+
end
|
75
|
+
|
64
76
|
private
|
65
77
|
attr_reader :semaphore, :calls
|
66
78
|
|
@@ -80,7 +92,6 @@ module Adhearsion
|
|
80
92
|
end
|
81
93
|
end
|
82
94
|
|
83
|
-
|
84
95
|
class FailedExtensionCallException < MetaAgiCallException; end
|
85
96
|
|
86
97
|
class HungupExtensionCallException < MetaAgiCallException; end
|
@@ -142,6 +153,33 @@ module Adhearsion
|
|
142
153
|
check_if_valid_call
|
143
154
|
define_variable_accessors
|
144
155
|
set_originating_voip_platform!
|
156
|
+
@tag_mutex = Mutex.new
|
157
|
+
@tags = []
|
158
|
+
end
|
159
|
+
|
160
|
+
def tags
|
161
|
+
@tag_mutex.synchronize do
|
162
|
+
return @tags.clone
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def tag(symbol)
|
167
|
+
raise ArgumentError, "tag must be a Symbol" unless symbol.is_a? Symbol
|
168
|
+
@tag_mutex.synchronize do
|
169
|
+
@tags << symbol
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def remove_tag(symbol)
|
174
|
+
@tag_mutex.synchronize do
|
175
|
+
@tags.reject! { |tag| tag == symbol }
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def tagged_with?(symbol)
|
180
|
+
@tag_mutex.synchronize do
|
181
|
+
@tags.include? symbol
|
182
|
+
end
|
145
183
|
end
|
146
184
|
|
147
185
|
def deliver_message(message)
|
@@ -237,6 +275,7 @@ module Adhearsion
|
|
237
275
|
replace_yes_no_answers_with_booleans
|
238
276
|
coerce_request_into_uri_object
|
239
277
|
decompose_uri_query_into_hash
|
278
|
+
override_variables_with_query_params
|
240
279
|
remove_dashes_from_context_name
|
241
280
|
coerce_type_of_number_into_symbol
|
242
281
|
}
|
@@ -315,7 +354,7 @@ module Adhearsion
|
|
315
354
|
returning variables do
|
316
355
|
if variables[:request].query
|
317
356
|
variables[:query] = variables[:request].query.split('&').inject({}) do |query_string_parameters, key_value_pair|
|
318
|
-
parameter_name, parameter_value = *key_value_pair.match(/(.+)=(
|
357
|
+
parameter_name, parameter_value = *key_value_pair.match(/(.+)=(.*)/).captures
|
319
358
|
query_string_parameters[parameter_name] = parameter_value
|
320
359
|
query_string_parameters
|
321
360
|
end
|
@@ -325,6 +364,16 @@ module Adhearsion
|
|
325
364
|
end
|
326
365
|
end
|
327
366
|
|
367
|
+
def override_variables_with_query_params(variables)
|
368
|
+
returning variables do
|
369
|
+
if variables[:query]
|
370
|
+
variables[:query].each do |key, value|
|
371
|
+
variables[key.to_sym] = value
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
328
377
|
def remove_dashes_from_context_name(variables)
|
329
378
|
returning variables do
|
330
379
|
variables[:context].gsub!('-', '_')
|
@@ -1,6 +1,4 @@
|
|
1
1
|
# Hardcoding require for now since for some reason it's not being loaded
|
2
|
-
require 'adhearsion/blank_slate'
|
3
|
-
require 'adhearsion/component_manager'
|
4
2
|
require 'adhearsion/voip/dsl/dialplan/control_passing_exception'
|
5
3
|
|
6
4
|
module Adhearsion
|
@@ -8,25 +6,40 @@ module Adhearsion
|
|
8
6
|
attr_accessor :loader, :entry_points
|
9
7
|
def initialize(loader = Loader)
|
10
8
|
@loader = loader
|
11
|
-
@entry_points = @loader.
|
9
|
+
@entry_points = @loader.load_dialplans.contexts
|
12
10
|
end
|
13
11
|
|
14
12
|
##
|
15
13
|
# Lookup and return an entry point by context name
|
14
|
+
#
|
16
15
|
def lookup(context_name)
|
17
16
|
entry_points[context_name]
|
18
17
|
end
|
19
18
|
|
20
19
|
##
|
21
|
-
# Executable environment for a dial plan in the scope of a call
|
20
|
+
# Executable environment for a dial plan in the scope of a call. This class has all the dialplan methods mixed into it.
|
21
|
+
#
|
22
22
|
class ExecutionEnvironment
|
23
23
|
|
24
|
+
class << self
|
25
|
+
def create(*args)
|
26
|
+
returning(new(*args)) { |instance| instance.stage! }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
24
30
|
attr_reader :call
|
25
|
-
def initialize(call, entry_point
|
31
|
+
def initialize(call, entry_point)
|
26
32
|
@call, @entry_point = call, entry_point
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Adds the methods to this ExecutionEnvironment which make it useful. e.g. dialplan-related methods, call variables,
|
37
|
+
# and component methods.
|
38
|
+
#
|
39
|
+
def stage!
|
27
40
|
extend_with_voip_commands!
|
28
41
|
extend_with_call_variables!
|
29
|
-
|
42
|
+
extend_with_dialplan_component_methods!
|
30
43
|
end
|
31
44
|
|
32
45
|
def run
|
@@ -41,27 +54,22 @@ module Adhearsion
|
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
ComponentManager.components_with_call_context['#{component_name}'].instantiate_with_call_context(self, *args, &block)
|
61
|
-
end
|
62
|
-
COMPONENT_BUILDER
|
63
|
-
end
|
64
|
-
end
|
57
|
+
protected
|
58
|
+
|
59
|
+
attr_reader :entry_point
|
60
|
+
def extend_with_voip_commands!
|
61
|
+
extend Adhearsion::VoIP::Conveniences
|
62
|
+
extend Adhearsion::VoIP::Commands.for(call.originating_voip_platform)
|
63
|
+
end
|
64
|
+
|
65
|
+
def extend_with_call_variables!
|
66
|
+
call.define_variable_accessors self
|
67
|
+
end
|
68
|
+
|
69
|
+
def extend_with_dialplan_component_methods!
|
70
|
+
Components.component_manager.extend_object_with(self, :dialplan) if Components.component_manager
|
71
|
+
end
|
72
|
+
|
65
73
|
end
|
66
74
|
|
67
75
|
class Manager
|
@@ -81,20 +89,19 @@ module Adhearsion
|
|
81
89
|
|
82
90
|
def handle(call)
|
83
91
|
if call.failed_call?
|
84
|
-
environment = ExecutionEnvironment.
|
85
|
-
call.extract_failed_reason_from
|
92
|
+
environment = ExecutionEnvironment.create(call, nil)
|
93
|
+
call.extract_failed_reason_from environment
|
86
94
|
raise FailedExtensionCallException.new(environment)
|
87
95
|
end
|
88
96
|
|
89
97
|
if call.hungup_call?
|
90
|
-
raise HungupExtensionCallException.new(ExecutionEnvironment.new(call))
|
98
|
+
raise HungupExtensionCallException.new(ExecutionEnvironment.new(call, nil))
|
91
99
|
end
|
92
100
|
|
93
101
|
starting_entry_point = entry_point_for call
|
94
102
|
raise NoContextError, "No dialplan entry point for call context '#{call.context}' -- Ignoring call!" unless starting_entry_point
|
95
|
-
|
96
|
-
@context
|
97
|
-
inject_context_names_into_environment(@context)
|
103
|
+
@context = ExecutionEnvironment.create(call, starting_entry_point)
|
104
|
+
inject_context_names_into_environment @context
|
98
105
|
@context.run
|
99
106
|
end
|
100
107
|
|
@@ -103,7 +110,7 @@ module Adhearsion
|
|
103
110
|
def entry_point_for(call)
|
104
111
|
if entry_point = dial_plan.lookup(call.context.to_sym)
|
105
112
|
entry_point
|
106
|
-
elsif m = call.request.path.match(%r{/([^/]+)})
|
113
|
+
elsif call.respond_to?(:request) && m = call.request.path.match(%r{/([^/]+)})
|
107
114
|
dial_plan.lookup(m[1].to_sym)
|
108
115
|
end
|
109
116
|
end
|
@@ -124,50 +131,55 @@ module Adhearsion
|
|
124
131
|
attr_accessor :default_dial_plan_file_name
|
125
132
|
|
126
133
|
def load(dial_plan_as_string)
|
127
|
-
|
128
|
-
|
129
|
-
|
134
|
+
string_io = StringIO.new dial_plan_as_string
|
135
|
+
def string_io.path
|
136
|
+
"(eval)"
|
130
137
|
end
|
138
|
+
load_dialplans string_io
|
131
139
|
end
|
132
140
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
141
|
+
def load_dialplans(*files)
|
142
|
+
files = Adhearsion::AHN_CONFIG.files_from_setting("paths", "dialplan") if files.empty?
|
143
|
+
files = Array files
|
144
|
+
files.map! do |file|
|
145
|
+
case file
|
146
|
+
when File, StringIO
|
147
|
+
file
|
148
|
+
when String
|
149
|
+
File.new file
|
150
|
+
else
|
151
|
+
raise ArgumentError, "Unrecognized type of file #{file.inspect}"
|
152
|
+
end
|
142
153
|
end
|
143
|
-
|
144
|
-
|
145
|
-
|
154
|
+
returning new do |loader|
|
155
|
+
files.each do |file|
|
156
|
+
loader.load file
|
157
|
+
end
|
146
158
|
end
|
147
|
-
|
159
|
+
end
|
160
|
+
|
148
161
|
end
|
149
162
|
|
150
163
|
self.default_dial_plan_file_name ||= 'dialplan.rb'
|
151
164
|
|
152
|
-
attr_reader :contexts
|
153
165
|
def initialize
|
154
|
-
@
|
166
|
+
@context_collector = ContextNameCollector.new
|
155
167
|
end
|
156
168
|
|
157
|
-
def
|
158
|
-
contexts
|
169
|
+
def contexts
|
170
|
+
@context_collector.contexts
|
171
|
+
end
|
172
|
+
|
173
|
+
def load(dialplan_file)
|
174
|
+
dialplan_code = dialplan_file.read
|
175
|
+
@context_collector.instance_eval(dialplan_code, dialplan_file.path)
|
176
|
+
nil
|
159
177
|
end
|
160
178
|
|
161
179
|
class ContextNameCollector# < ::BlankSlate
|
162
180
|
|
163
181
|
class << self
|
164
|
-
|
165
|
-
def build(dial_plan_as_string)
|
166
|
-
builder = new
|
167
|
-
builder.instance_eval(dial_plan_as_string)
|
168
|
-
builder.contexts
|
169
|
-
end
|
170
|
-
|
182
|
+
|
171
183
|
def const_missing(name)
|
172
184
|
super
|
173
185
|
rescue ArgumentError
|
@@ -185,6 +197,7 @@ module Adhearsion
|
|
185
197
|
super if !block_given? || args.any?
|
186
198
|
contexts[name] = DialplanContextProc.new(name, &block)
|
187
199
|
end
|
200
|
+
|
188
201
|
end
|
189
202
|
end
|
190
203
|
class DialplanContextProc < Proc
|
@@ -15,7 +15,7 @@
|
|
15
15
|
# License along with this library; if not, write to the Free Software
|
16
16
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17
17
|
|
18
|
-
require 'adhearsion/
|
18
|
+
require 'adhearsion/foundation/metaprogramming'
|
19
19
|
require 'adhearsion/voip/conveniences'
|
20
20
|
require 'adhearsion/voip/constants'
|
21
21
|
require 'adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches'
|
@@ -14,14 +14,10 @@ module Adhearsion
|
|
14
14
|
|
15
15
|
#TODO: separate into smaller pieces
|
16
16
|
def self.get_contexts
|
17
|
-
unless Adhearsion::Paths.manager_for?("dialplans")
|
18
|
-
raise "No dialplan files found in .ahnrc!"
|
19
|
-
end
|
20
|
-
|
21
17
|
envelope = ContextsEnvelope.new
|
22
18
|
|
23
|
-
dialplans =
|
24
|
-
warn "No dialplan files were found!" if dialplans.empty?
|
19
|
+
dialplans = AHN_CONFIG.files_from_setting "paths", "dialplan"
|
20
|
+
ahn_log.dialplan.warn "No dialplan files were found!" if dialplans.empty?
|
25
21
|
|
26
22
|
returning({}) do |contexts|
|
27
23
|
dialplans.each do |file|
|
@@ -52,10 +52,10 @@ module Adhearsion
|
|
52
52
|
|
53
53
|
# Checks against a pattern identifying US local numbers (i.e numbers
|
54
54
|
# without an area code seven digits long)
|
55
|
-
def
|
55
|
+
def us_local_number?() to_s =~ Adhearsion::VoIP::Constants::US_LOCAL_NUMBER end
|
56
56
|
|
57
57
|
# Checks against a pattern identifying US domestic numbers.
|
58
|
-
def
|
58
|
+
def us_national_number?() to_s =~ Adhearsion::VoIP::Constants::US_NATIONAL_NUMBER end
|
59
59
|
|
60
60
|
# Checks against a pattern identifying an ISN number. See http://freenum.org
|
61
61
|
# for more info.
|
@@ -52,7 +52,7 @@ module Adhearsion
|
|
52
52
|
# If the target context does not exist, warn and don't handle the call
|
53
53
|
unless first_context
|
54
54
|
log "No context '#{first_context_name}' found in " +
|
55
|
-
"#{
|
55
|
+
"#{AHN_CONFIG.files_from_setting("paths", "").to_sentence(:connector => "or")}. Ignoring request!"
|
56
56
|
return
|
57
57
|
end
|
58
58
|
|
@@ -91,7 +91,7 @@ module Adhearsion
|
|
91
91
|
# time.
|
92
92
|
def should_reload_contexts?
|
93
93
|
!@abstract_contexts || !@abstract_dispatcher ||
|
94
|
-
|
94
|
+
AHN_CONFIG.files_from_setting("paths", "dialplan").map { |x| File.mtime(x) }.max < Time.now
|
95
95
|
end
|
96
96
|
|
97
97
|
def rubyize_keys_for(hash)
|
data/lib/theatre.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
require 'theatre/version'
|
7
|
+
require 'theatre/namespace_manager'
|
8
|
+
require 'theatre/invocation'
|
9
|
+
require 'theatre/callback_definition_loader'
|
10
|
+
|
11
|
+
module Theatre
|
12
|
+
|
13
|
+
class Theatre
|
14
|
+
|
15
|
+
attr_reader :namespace_manager
|
16
|
+
|
17
|
+
##
|
18
|
+
# Creates a new stopped Theatre. You must call start!() after you instantiate this for it to begin processing events.
|
19
|
+
#
|
20
|
+
# @param [Fixnum] thread_count Number of Threads to spawn when started.
|
21
|
+
#
|
22
|
+
def initialize(thread_count=6)
|
23
|
+
@thread_count = thread_count
|
24
|
+
@started = false
|
25
|
+
@namespace_manager = ActorNamespaceManager.new
|
26
|
+
@thread_group = ThreadGroup.new
|
27
|
+
@master_queue = Queue.new
|
28
|
+
@loader_mixins = []
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Send a message to this Theatre for asynchronous processing.
|
33
|
+
#
|
34
|
+
# @param [String] namespace The namespace to which the payload should be sent
|
35
|
+
# @param [Object] payload The actual content to be sent to the callback. Optional.
|
36
|
+
# @return [Array<Theatre::Invocation>] An Array of Invocation objects
|
37
|
+
# @raise Theatre::NamespaceNotFound Raised when told to enqueue an unrecognized namespace
|
38
|
+
#
|
39
|
+
def trigger(namespace, payload=:argument_undefined)
|
40
|
+
@namespace_manager.callbacks_for_namespaces(namespace).map do |callback|
|
41
|
+
invocation = if payload.equal?(:argument_undefined)
|
42
|
+
Invocation.new(namespace, callback)
|
43
|
+
else
|
44
|
+
Invocation.new(namespace, callback, payload)
|
45
|
+
end
|
46
|
+
invocation.queued
|
47
|
+
@master_queue << invocation
|
48
|
+
invocation
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Send a message to this Theatre for synchronous processing. The execution of this will not go through this Theatre's
|
54
|
+
# Thread pool. If an error occurred in any of callbacks, the Exception object will be placed in the returned Array
|
55
|
+
# instead for you to act upon.
|
56
|
+
#
|
57
|
+
# @param [String] namespace The namespace to which the payload should be sent
|
58
|
+
# @param [Object] payload The actual content to be sent to the callback. Optional.
|
59
|
+
# @return [Array] An Array containing each callback's return value (or Exception raised, if any) when given the payload
|
60
|
+
# @raise Theatre::NamespaceNotFound Raised when told to enqueue an unrecognized namespace
|
61
|
+
#
|
62
|
+
def trigger_immediately(namespace, payload=:argument_undefined)
|
63
|
+
@namespace_manager.callbacks_for_namespaces(namespace).map do |callback|
|
64
|
+
begin
|
65
|
+
invocation = if payload.equal?(:argument_undefined)
|
66
|
+
callback.call
|
67
|
+
else
|
68
|
+
callback.call payload
|
69
|
+
end
|
70
|
+
rescue => captured_error_to_be_returned
|
71
|
+
captured_error_to_be_returned
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_events_code(code, *args)
|
77
|
+
loader = CallbackDefinitionLoader.new(self, *args)
|
78
|
+
loader.load_events_code code
|
79
|
+
end
|
80
|
+
|
81
|
+
def load_events_file(file, *args)
|
82
|
+
loader = CallbackDefinitionLoader.new(self, *args)
|
83
|
+
loader.load_events_file file
|
84
|
+
end
|
85
|
+
|
86
|
+
def register_namespace_name(*args)
|
87
|
+
@namespace_manager.register_namespace_name(*args)
|
88
|
+
end
|
89
|
+
|
90
|
+
def register_callback_at_namespace(*args)
|
91
|
+
@namespace_manager.register_callback_at_namespace(*args)
|
92
|
+
end
|
93
|
+
|
94
|
+
def register_loader_mixin(mod)
|
95
|
+
@loader_mixins << mod
|
96
|
+
end
|
97
|
+
|
98
|
+
def join
|
99
|
+
@thread_group.list.each do |thread|
|
100
|
+
begin
|
101
|
+
thread.join
|
102
|
+
rescue
|
103
|
+
# Ignore any exceptions
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Starts this Theatre.
|
110
|
+
#
|
111
|
+
# When this method is called, the Threads are spawned and begin pulling messages off this Theatre's master queue.
|
112
|
+
#
|
113
|
+
def start!
|
114
|
+
return false if @thread_group.list.any? # Already started
|
115
|
+
@started_time = Time.now
|
116
|
+
@thread_count.times do
|
117
|
+
@thread_group.add Thread.new(&method(:thread_loop))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Notifies all Threads for this Theatre to stop by sending them special messages. Any messages which were queued and
|
123
|
+
# untriggered when this method is received will still be processed. Note: you may start this Theatre again later once it
|
124
|
+
# has been stopped.
|
125
|
+
#
|
126
|
+
def graceful_stop!
|
127
|
+
@thread_count.times { @master_queue << :THEATRE_SHUTDOWN! }
|
128
|
+
@started_time = nil
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
# This will use the Adhearsion logger eventually.
|
134
|
+
def warn(exception)
|
135
|
+
# STDERR.puts exception.message, *exception.backtrace
|
136
|
+
end
|
137
|
+
|
138
|
+
def thread_loop
|
139
|
+
loop do
|
140
|
+
begin
|
141
|
+
next_invocation = @master_queue.pop
|
142
|
+
return :stopped if next_invocation.equal? :THEATRE_SHUTDOWN!
|
143
|
+
next_invocation.start
|
144
|
+
rescue => error
|
145
|
+
warn error
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|