adhearsion 0.8.3 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -2
- data/EVENTS +1 -1
- data/Rakefile +4 -4
- data/adhearsion.gemspec +8 -4
- data/app_generators/ahn/USAGE +3 -3
- data/app_generators/ahn/ahn_generator.rb +11 -11
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +3 -3
- data/app_generators/ahn/templates/components/disabled/restful_rpc/example-client.rb +6 -6
- data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb +16 -16
- data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +42 -42
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +11 -11
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +1 -1
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +6 -6
- data/app_generators/ahn/templates/components/simon_game/simon_game.rb +4 -4
- data/app_generators/ahn/templates/config/startup.rb +31 -16
- data/bin/ahn +3 -3
- data/bin/ahnctl +8 -8
- data/bin/jahn +3 -3
- data/examples/asterisk_manager_interface/standalone.rb +2 -2
- data/lib/adhearsion.rb +4 -2
- data/lib/adhearsion/cli.rb +31 -31
- data/lib/adhearsion/component_manager.rb +39 -39
- data/lib/adhearsion/component_manager/component_tester.rb +14 -14
- data/lib/adhearsion/component_manager/spec_framework.rb +1 -1
- data/lib/adhearsion/events_support.rb +12 -12
- data/lib/adhearsion/foundation/blank_slate.rb +1 -1
- data/lib/adhearsion/foundation/custom_daemonizer.rb +2 -2
- data/lib/adhearsion/foundation/event_socket.rb +26 -26
- data/lib/adhearsion/foundation/future_resource.rb +6 -6
- data/lib/adhearsion/foundation/metaprogramming.rb +2 -2
- data/lib/adhearsion/foundation/numeric.rb +3 -3
- data/lib/adhearsion/foundation/relationship_properties.rb +7 -7
- data/lib/adhearsion/foundation/string.rb +8 -8
- data/lib/adhearsion/foundation/synchronized_hash.rb +8 -8
- data/lib/adhearsion/host_definitions.rb +16 -16
- data/lib/adhearsion/initializer.rb +74 -65
- data/lib/adhearsion/initializer/asterisk.rb +15 -9
- data/lib/adhearsion/initializer/configuration.rb +54 -39
- data/lib/adhearsion/initializer/database.rb +4 -4
- data/lib/adhearsion/initializer/drb.rb +6 -6
- data/lib/adhearsion/initializer/freeswitch.rb +1 -1
- data/lib/adhearsion/initializer/ldap.rb +51 -0
- data/lib/adhearsion/initializer/rails.rb +8 -8
- data/lib/adhearsion/logging.rb +16 -16
- data/lib/adhearsion/tasks/deprecations.rb +12 -12
- data/lib/adhearsion/tasks/generating.rb +2 -2
- data/lib/adhearsion/tasks/testing.rb +7 -7
- data/lib/adhearsion/version.rb +1 -1
- data/lib/adhearsion/voip/asterisk/agi_server.rb +44 -14
- data/lib/adhearsion/voip/asterisk/commands.rb +281 -237
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +8 -8
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +14 -14
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +16 -16
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +39 -39
- data/lib/adhearsion/voip/asterisk/config_manager.rb +13 -13
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +91 -87
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +739 -739
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +60 -60
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +16 -16
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +1 -1
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +13 -13
- data/lib/adhearsion/voip/asterisk/super_manager.rb +3 -3
- data/lib/adhearsion/voip/call.rb +101 -64
- data/lib/adhearsion/voip/call_routing.rb +9 -9
- data/lib/adhearsion/voip/constants.rb +7 -7
- data/lib/adhearsion/voip/conveniences.rb +1 -1
- data/lib/adhearsion/voip/dial_plan.rb +42 -40
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +27 -27
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +1 -1
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +6 -6
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +17 -17
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +7 -7
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +2 -2
- data/lib/adhearsion/voip/dsl/numerical_string.rb +3 -3
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +7 -7
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +1 -1
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +20 -20
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +5 -5
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +33 -33
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +1 -1
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +2 -2
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +9 -9
- data/lib/theatre.rb +18 -18
- data/lib/theatre/callback_definition_loader.rb +17 -17
- data/lib/theatre/guid.rb +6 -6
- data/lib/theatre/invocation.rb +19 -19
- data/lib/theatre/namespace_manager.rb +28 -28
- metadata +55 -14
@@ -2,16 +2,16 @@ module Adhearsion
|
|
2
2
|
module VoIP
|
3
3
|
module Asterisk
|
4
4
|
module Manager
|
5
|
-
|
5
|
+
|
6
6
|
##
|
7
7
|
# Higher level abstraction of the Asterisk Manager Interface.
|
8
8
|
#
|
9
9
|
class SuperManager
|
10
|
-
|
10
|
+
|
11
11
|
def initialize
|
12
12
|
raise NotImplementedError
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
data/lib/adhearsion/voip/call.rb
CHANGED
@@ -5,21 +5,21 @@ module Adhearsion
|
|
5
5
|
def active_calls
|
6
6
|
@calls ||= Calls.new
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def receive_call_from(io, &block)
|
10
10
|
active_calls << (call = Call.receive_from(io, &block))
|
11
11
|
call
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def remove_inactive_call(call)
|
15
15
|
active_calls.remove_inactive_call(call)
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
class Hangup < Exception
|
20
20
|
# At the moment, we'll just use this to end a call-handling Thread.
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
##
|
24
24
|
# This manages the list of calls the Adhearsion service receives
|
25
25
|
class Calls
|
@@ -27,44 +27,44 @@ module Adhearsion
|
|
27
27
|
@semaphore = Monitor.new
|
28
28
|
@calls = {}
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def <<(call)
|
32
32
|
atomically do
|
33
33
|
calls[call.unique_identifier] = call
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def any?
|
38
38
|
atomically do
|
39
39
|
!calls.empty?
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def size
|
44
44
|
atomically do
|
45
45
|
calls.size
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def remove_inactive_call(call)
|
50
50
|
atomically do
|
51
51
|
calls.delete call.unique_identifier
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
# Searches all active calls by their unique_identifier. See Call#unique_identifier.
|
56
56
|
def find(id)
|
57
57
|
atomically do
|
58
58
|
return calls[id]
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
def clear!
|
63
63
|
atomically do
|
64
64
|
calls.clear
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def with_tag(tag)
|
69
69
|
atomically do
|
70
70
|
calls.inject(Array.new) do |calls_with_tag,(key,call)|
|
@@ -72,22 +72,22 @@ module Adhearsion
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
def to_a
|
77
77
|
calls.values
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
private
|
81
81
|
attr_reader :semaphore, :calls
|
82
|
-
|
82
|
+
|
83
83
|
def atomically(&block)
|
84
84
|
semaphore.synchronize(&block)
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
class UselessCallException < Exception; end
|
90
|
-
|
90
|
+
|
91
91
|
class MetaAgiCallException < Exception
|
92
92
|
attr_reader :call
|
93
93
|
def initialize(call)
|
@@ -95,17 +95,50 @@ module Adhearsion
|
|
95
95
|
@call = call
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
class FailedExtensionCallException < MetaAgiCallException; end
|
100
|
-
|
100
|
+
|
101
101
|
class HungupExtensionCallException < MetaAgiCallException; end
|
102
|
-
|
102
|
+
|
103
103
|
##
|
104
104
|
# Encapsulates call-related data and behavior.
|
105
105
|
# For example, variables passed in on call initiation are
|
106
|
-
# accessible here as attributes
|
106
|
+
# accessible here as attributes
|
107
107
|
class Call
|
108
|
-
|
108
|
+
|
109
|
+
##
|
110
|
+
# Wraps the Queue object (subclasses it) so we can handle runaway threads,
|
111
|
+
# namely those originating from using with_next_message in commands.rb - this
|
112
|
+
# overrides << to check for the :cancel symbol and trigger the automessaging_tainted
|
113
|
+
# instance variable.
|
114
|
+
class CallMessageQueue < Queue
|
115
|
+
|
116
|
+
class InboxClosedException < Exception
|
117
|
+
# this gets raised when the :cancel message is delivered to the queue and with_next_message (or similar auto-message-iteration)
|
118
|
+
# features are called.
|
119
|
+
end
|
120
|
+
|
121
|
+
attr_reader :open
|
122
|
+
|
123
|
+
def initialize
|
124
|
+
@open = true
|
125
|
+
super
|
126
|
+
end
|
127
|
+
|
128
|
+
def <<(queue_obj)
|
129
|
+
@open = false if queue_obj == :cancel
|
130
|
+
super(queue_obj)
|
131
|
+
end
|
132
|
+
|
133
|
+
def pop
|
134
|
+
raise Adhearsion::Call::CallMessageQueue::InboxClosedException, "The message queue for this call has aleady been disabled." if !@open
|
135
|
+
super
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
|
109
142
|
# This is basically a translation of ast_channel_reason2str() from main/channel.c and
|
110
143
|
# ast_control_frame_type in include/asterisk/frame.h in the Asterisk source code. When
|
111
144
|
# Asterisk jumps to the 'failed' extension, it sets a REASON channel variable to a number.
|
@@ -131,8 +164,8 @@ module Adhearsion
|
|
131
164
|
:unhold, # Indicate call is left from hold
|
132
165
|
:vidupdate # Indicate video frame update
|
133
166
|
]
|
134
|
-
|
135
|
-
|
167
|
+
|
168
|
+
|
136
169
|
class << self
|
137
170
|
##
|
138
171
|
# The primary public interface for creating a Call instance.
|
@@ -143,14 +176,14 @@ module Adhearsion
|
|
143
176
|
block.call(call) if block
|
144
177
|
end
|
145
178
|
end
|
146
|
-
|
179
|
+
|
147
180
|
private
|
148
181
|
def variable_parser_for(io)
|
149
182
|
Variables::Parser.parse(io)
|
150
183
|
end
|
151
|
-
|
184
|
+
|
152
185
|
end
|
153
|
-
|
186
|
+
|
154
187
|
attr_accessor :io, :type, :variables, :originating_voip_platform, :inbox
|
155
188
|
def initialize(io, variables)
|
156
189
|
@io, @variables = io, variables.symbolize_keys
|
@@ -173,13 +206,13 @@ module Adhearsion
|
|
173
206
|
@tags << symbol
|
174
207
|
end
|
175
208
|
end
|
176
|
-
|
209
|
+
|
177
210
|
def remove_tag(symbol)
|
178
211
|
@tag_mutex.synchronize do
|
179
212
|
@tags.reject! { |tag| tag == symbol }
|
180
213
|
end
|
181
214
|
end
|
182
|
-
|
215
|
+
|
183
216
|
def tagged_with?(symbol)
|
184
217
|
@tag_mutex.synchronize do
|
185
218
|
@tags.include? symbol
|
@@ -191,8 +224,12 @@ module Adhearsion
|
|
191
224
|
end
|
192
225
|
alias << deliver_message
|
193
226
|
|
227
|
+
def can_use_messaging?
|
228
|
+
return inbox.open == true
|
229
|
+
end
|
230
|
+
|
194
231
|
def inbox
|
195
|
-
@inbox ||=
|
232
|
+
@inbox ||= CallMessageQueue.new
|
196
233
|
end
|
197
234
|
|
198
235
|
def hangup!
|
@@ -203,18 +240,18 @@ module Adhearsion
|
|
203
240
|
def closed?
|
204
241
|
io.closed?
|
205
242
|
end
|
206
|
-
|
243
|
+
|
207
244
|
# Asterisk sometimes uses the "failed" extension to indicate a failed dial attempt.
|
208
245
|
# Since it may be important to handle these, this flag helps the dialplan Manager
|
209
246
|
# figure that out.
|
210
247
|
def failed_call?
|
211
248
|
@failed_call
|
212
249
|
end
|
213
|
-
|
250
|
+
|
214
251
|
def hungup_call?
|
215
252
|
@hungup_call
|
216
253
|
end
|
217
|
-
|
254
|
+
|
218
255
|
# Adhearsion indexes calls by this identifier so they may later be found and manipulated. For calls from Asterisk, this
|
219
256
|
# method uses the following properties for uniqueness, falling back to the next if one is for some reason unavailable:
|
220
257
|
#
|
@@ -230,13 +267,13 @@ module Adhearsion
|
|
230
267
|
raise NotImplementedError
|
231
268
|
end
|
232
269
|
end
|
233
|
-
|
270
|
+
|
234
271
|
def define_variable_accessors(recipient=self)
|
235
|
-
variables.each do |key, value|
|
272
|
+
variables.each do |key, value|
|
236
273
|
define_singleton_accessor_with_pair(key, value, recipient)
|
237
274
|
end
|
238
275
|
end
|
239
|
-
|
276
|
+
|
240
277
|
def extract_failed_reason_from(environment)
|
241
278
|
if originating_voip_platform == :asterisk
|
242
279
|
failed_reason = environment.variable 'REASON'
|
@@ -244,30 +281,30 @@ module Adhearsion
|
|
244
281
|
define_singleton_accessor_with_pair(:failed_reason, failed_reason, environment)
|
245
282
|
end
|
246
283
|
end
|
247
|
-
|
284
|
+
|
248
285
|
private
|
249
|
-
|
286
|
+
|
250
287
|
def define_singleton_accessor_with_pair(key, value, recipient=self)
|
251
288
|
recipient.metaclass.send :attr_accessor, key unless recipient.class.respond_to?("#{key}=")
|
252
289
|
recipient.send "#{key}=", value
|
253
290
|
end
|
254
|
-
|
291
|
+
|
255
292
|
def check_if_valid_call
|
256
293
|
extension = variables[:extension]
|
257
294
|
@failed_call = true if extension == 'failed'
|
258
295
|
@hungup_call = true if extension == 'h'
|
259
296
|
raise UselessCallException if extension == 't' # TODO: Move this whole method to Manager
|
260
297
|
end
|
261
|
-
|
298
|
+
|
262
299
|
def set_originating_voip_platform!
|
263
300
|
# TODO: we can make this determination programatically at some point,
|
264
301
|
# but it will probably involve a bit more engineering than just a case statement (like
|
265
302
|
# subclasses of Call for the various platforms), so we'll be totally cheap for now.
|
266
303
|
self.originating_voip_platform = :asterisk
|
267
304
|
end
|
268
|
-
|
305
|
+
|
269
306
|
module Variables
|
270
|
-
|
307
|
+
|
271
308
|
module Coercions
|
272
309
|
|
273
310
|
COERCION_ORDER = %w{
|
@@ -285,7 +322,7 @@ module Adhearsion
|
|
285
322
|
}
|
286
323
|
|
287
324
|
class << self
|
288
|
-
|
325
|
+
|
289
326
|
def remove_agi_prefixes_from_keys_and_strip_whitespace(variables)
|
290
327
|
variables.inject({}) do |new_variables,(key,value)|
|
291
328
|
returning new_variables do
|
@@ -294,7 +331,7 @@ module Adhearsion
|
|
294
331
|
end
|
295
332
|
end
|
296
333
|
end
|
297
|
-
|
334
|
+
|
298
335
|
def coerce_keys_into_symbols(variables)
|
299
336
|
variables.inject({}) do |new_variables,(key,value)|
|
300
337
|
returning new_variables do
|
@@ -302,13 +339,13 @@ module Adhearsion
|
|
302
339
|
end
|
303
340
|
end
|
304
341
|
end
|
305
|
-
|
342
|
+
|
306
343
|
def coerce_extension_into_phone_number_object(variables)
|
307
344
|
returning variables do
|
308
345
|
variables[:extension] = Adhearsion::VoIP::DSL::PhoneNumber.new(variables[:extension])
|
309
346
|
end
|
310
347
|
end
|
311
|
-
|
348
|
+
|
312
349
|
def coerce_numerical_values_to_numerics(variables)
|
313
350
|
variables.inject({}) do |vars,(key,value)|
|
314
351
|
returning vars do
|
@@ -344,19 +381,19 @@ module Adhearsion
|
|
344
381
|
def replace_yes_no_answers_with_booleans(variables)
|
345
382
|
variables.each do |key,value|
|
346
383
|
case value
|
347
|
-
when 'yes'
|
348
|
-
when 'no'
|
384
|
+
when 'yes' then variables[key] = true
|
385
|
+
when 'no' then variables[key] = false
|
349
386
|
end
|
350
387
|
end
|
351
388
|
end
|
352
|
-
|
389
|
+
|
353
390
|
def coerce_request_into_uri_object(variables)
|
354
391
|
if variables[:request]
|
355
392
|
variables[:request] = URI.parse(variables[:request]) unless variables[:request].kind_of? URI
|
356
393
|
end
|
357
394
|
variables
|
358
395
|
end
|
359
|
-
|
396
|
+
|
360
397
|
def coerce_type_of_number_into_symbol(variables)
|
361
398
|
returning variables do
|
362
399
|
variables[:type_of_calling_number] = Adhearsion::VoIP::Constants::Q931_TYPE_OF_NUMBER[variables.delete(:callington).to_i]
|
@@ -376,7 +413,7 @@ module Adhearsion
|
|
376
413
|
end
|
377
414
|
end
|
378
415
|
end
|
379
|
-
|
416
|
+
|
380
417
|
def override_variables_with_query_params(variables)
|
381
418
|
returning variables do
|
382
419
|
if variables[:query]
|
@@ -386,50 +423,50 @@ module Adhearsion
|
|
386
423
|
end
|
387
424
|
end
|
388
425
|
end
|
389
|
-
|
426
|
+
|
390
427
|
def remove_dashes_from_context_name(variables)
|
391
428
|
returning variables do
|
392
429
|
variables[:context].gsub!('-', '_')
|
393
430
|
end
|
394
431
|
end
|
395
|
-
|
432
|
+
|
396
433
|
end
|
397
434
|
end
|
398
435
|
|
399
436
|
class Parser
|
400
|
-
|
437
|
+
|
401
438
|
class << self
|
402
439
|
def parse(*args, &block)
|
403
440
|
returning new(*args, &block) do |parser|
|
404
441
|
parser.parse
|
405
442
|
end
|
406
443
|
end
|
407
|
-
|
444
|
+
|
408
445
|
def coerce_variables(variables)
|
409
446
|
Coercions::COERCION_ORDER.inject(variables) do |tmp_variables, coercing_method_name|
|
410
447
|
Coercions.send(coercing_method_name, tmp_variables)
|
411
448
|
end
|
412
449
|
end
|
413
|
-
|
450
|
+
|
414
451
|
def separate_line_into_key_value_pair(line)
|
415
452
|
line.match(/^([^:]+):\s?(.+)/).captures
|
416
453
|
end
|
417
454
|
end
|
418
|
-
|
455
|
+
|
419
456
|
attr_reader :io, :variables, :lines
|
420
457
|
def initialize(io)
|
421
458
|
@io = io
|
422
459
|
@lines = []
|
423
460
|
end
|
424
|
-
|
461
|
+
|
425
462
|
def parse
|
426
463
|
extract_variable_lines_from_io
|
427
464
|
initialize_variables_as_hash_from_lines
|
428
465
|
@variables = self.class.coerce_variables(variables)
|
429
466
|
end
|
430
|
-
|
467
|
+
|
431
468
|
private
|
432
|
-
|
469
|
+
|
433
470
|
def initialize_variables_as_hash_from_lines
|
434
471
|
@variables = lines.inject({}) do |new_variables,line|
|
435
472
|
returning new_variables do
|
@@ -438,16 +475,16 @@ module Adhearsion
|
|
438
475
|
end
|
439
476
|
end
|
440
477
|
end
|
441
|
-
|
478
|
+
|
442
479
|
def extract_variable_lines_from_io
|
443
480
|
while line = io.readline.chomp
|
444
481
|
break if line.empty?
|
445
482
|
@lines << line
|
446
483
|
end
|
447
484
|
end
|
448
|
-
|
485
|
+
|
449
486
|
end
|
450
|
-
|
487
|
+
|
451
488
|
end
|
452
|
-
end
|
489
|
+
end
|
453
490
|
end
|