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
@@ -3,7 +3,7 @@ module Adhearsion
|
|
3
3
|
module VoIP
|
4
4
|
module Asterisk
|
5
5
|
class ConfigurationManager
|
6
|
-
|
6
|
+
|
7
7
|
class << self
|
8
8
|
def normalize_configuration(file_contents)
|
9
9
|
# cat sip.conf | sed -e 's/\s*;.*$//g' | sed -e '/^;.*$/d' | sed -e '/^\s*$/d'
|
@@ -12,39 +12,39 @@ module Adhearsion
|
|
12
12
|
end.join("\n").squeeze("\n")
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
attr_reader :filename
|
17
|
-
|
17
|
+
|
18
18
|
def initialize(filename)
|
19
19
|
@filename = filename
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def sections
|
23
23
|
@sections ||= read_configuration
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def [](section_name)
|
27
27
|
result = sections.find { |(name, *rest)| section_name == name }
|
28
28
|
result.last if result
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def delete_section(section_name)
|
32
32
|
sections.reject! { |(name, *rest)| section_name == name }
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def new_section(name, properties={})
|
36
36
|
sections << [name, properties]
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
private
|
40
|
-
|
40
|
+
|
41
41
|
def read_configuration
|
42
42
|
normalized_file = self.class.normalize_configuration execute(read_command)
|
43
43
|
normalized_file.split(/^\[([-_\w]+)\]$/)[1..-1].enum_slice(2).map do |(name,properties)|
|
44
44
|
[name, hash_from_properties(properties)]
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def hash_from_properties(properties)
|
49
49
|
properties.split(/\n+/).inject({}) do |property_hash,property|
|
50
50
|
all, name, value = *property.match(/^\s*([^=]+?)\s*=\s*(.+)\s*$/)
|
@@ -53,15 +53,15 @@ module Adhearsion
|
|
53
53
|
property_hash
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def execute(command)
|
58
58
|
%x[command]
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def read_command
|
62
62
|
"cat #{filename}"
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -3,7 +3,7 @@ require 'adhearsion/voip/asterisk/manager_interface/ami_lexer'
|
|
3
3
|
module Adhearsion
|
4
4
|
module VoIP
|
5
5
|
module Asterisk
|
6
|
-
|
6
|
+
|
7
7
|
##
|
8
8
|
# Sorry, this AMI class has been deprecated. Please see http://docs.adhearsion.com/Asterisk_Manager_Interface for
|
9
9
|
# documentation on the new way of handling AMI. This new version is much better and should not require an enormous
|
@@ -11,14 +11,14 @@ module Adhearsion
|
|
11
11
|
#
|
12
12
|
class AMI
|
13
13
|
def initialize
|
14
|
-
raise "Sorry, this AMI class has been deprecated. Please see http://docs.adhearsion.com/
|
14
|
+
raise "Sorry, this AMI class has been deprecated. Please see http://docs.adhearsion.com/display/adhearsion/Asterisk+Manager+Interface for documentation on the new way of handling AMI. This new version is much better and should not require an enormous migration on your part."
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
mattr_accessor :manager_interface
|
19
|
-
|
19
|
+
|
20
20
|
module Manager
|
21
|
-
|
21
|
+
|
22
22
|
##
|
23
23
|
# This class abstracts a connection to the Asterisk Manager Interface. Its purpose is, first and foremost, to make
|
24
24
|
# the protocol consistent. Though the classes employed to assist this class (ManagerInterfaceAction,
|
@@ -28,17 +28,17 @@ module Adhearsion
|
|
28
28
|
# For a higher-level abstraction of the Asterisk Manager Interface, see the SuperManager class.
|
29
29
|
#
|
30
30
|
class ManagerInterface
|
31
|
-
|
31
|
+
|
32
32
|
CAUSAL_EVENT_NAMES = ["queuestatus", "sippeers", "parkedcalls", "status", "dahdishowchannels"] unless defined? CAUSAL_EVENT_NAMES
|
33
|
-
|
33
|
+
|
34
34
|
class << self
|
35
|
-
|
35
|
+
|
36
36
|
def connect(*args)
|
37
37
|
returning new(*args) do |connection|
|
38
38
|
connection.connect!
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def replies_with_action_id?(name, headers={})
|
43
43
|
name = name.to_s.downcase
|
44
44
|
# TODO: Expand this case statement
|
@@ -47,15 +47,15 @@ module Adhearsion
|
|
47
47
|
false
|
48
48
|
else
|
49
49
|
true
|
50
|
-
end
|
50
|
+
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
##
|
54
54
|
# When sending an action with "causal events" (i.e. events which must be collected to form a proper
|
55
55
|
# response), AMI should send a particular event which instructs us that no more events will be sent.
|
56
56
|
# This event is called the "causal event terminator".
|
57
57
|
#
|
58
|
-
# Note: you must supply both the name of the event and any headers because it's possible that some uses of an
|
58
|
+
# Note: you must supply both the name of the event and any headers because it's possible that some uses of an
|
59
59
|
# action (i.e. same name, different headers) have causal events while other uses don't.
|
60
60
|
#
|
61
61
|
# @param [String] name the name of the event
|
@@ -65,16 +65,16 @@ module Adhearsion
|
|
65
65
|
def has_causal_events?(name, headers={})
|
66
66
|
CAUSAL_EVENT_NAMES.include? name.to_s.downcase
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
##
|
70
70
|
# Used to determine the event name for an action which has causal events.
|
71
|
-
#
|
71
|
+
#
|
72
72
|
# @param [String] action_name
|
73
73
|
# @return [String] The corresponding event name which signals the completion of the causal event sequence.
|
74
|
-
#
|
74
|
+
#
|
75
75
|
def causal_event_terminator_name_for(action_name)
|
76
76
|
return nil unless has_causal_events?(action_name)
|
77
|
-
action_name = action_name.to_s.downcase
|
77
|
+
action_name = action_name.to_s.downcase
|
78
78
|
case action_name
|
79
79
|
when "queuestatus", 'parkedcalls', "status"
|
80
80
|
action_name + "complete"
|
@@ -82,9 +82,9 @@ module Adhearsion
|
|
82
82
|
"peerlistcomplete"
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
DEFAULT_SETTINGS = {
|
89
89
|
:host => "localhost",
|
90
90
|
:port => 5038,
|
@@ -92,9 +92,9 @@ module Adhearsion
|
|
92
92
|
:password => "secret",
|
93
93
|
:events => true
|
94
94
|
}.freeze unless defined? DEFAULT_SETTINGS
|
95
|
-
|
95
|
+
|
96
96
|
attr_reader *DEFAULT_SETTINGS.keys
|
97
|
-
|
97
|
+
|
98
98
|
##
|
99
99
|
# Creates a new Asterisk Manager Interface connection and exposes certain methods to control it. The constructor
|
100
100
|
# takes named parameters as Symbols. Note: if the :events option is given, this library will establish a separate
|
@@ -105,46 +105,46 @@ module Adhearsion
|
|
105
105
|
#
|
106
106
|
def initialize(options={})
|
107
107
|
options = parse_options options
|
108
|
-
|
108
|
+
|
109
109
|
@host = options[:host]
|
110
|
-
@username = options[:username]
|
110
|
+
@username = options[:username]
|
111
111
|
@password = options[:password]
|
112
112
|
@port = options[:port]
|
113
113
|
@events = options[:events]
|
114
|
-
|
114
|
+
|
115
115
|
@sent_messages = {}
|
116
116
|
@sent_messages_lock = Mutex.new
|
117
|
-
|
117
|
+
|
118
118
|
@actions_lexer = DelegatingAsteriskManagerInterfaceLexer.new self, \
|
119
119
|
:message_received => :action_message_received,
|
120
120
|
:error_received => :action_error_received
|
121
|
-
|
121
|
+
|
122
122
|
@write_queue = Queue.new
|
123
|
-
|
123
|
+
|
124
124
|
if @events
|
125
125
|
@events_lexer = DelegatingAsteriskManagerInterfaceLexer.new self, \
|
126
126
|
:message_received => :event_message_received,
|
127
|
-
:error_received => :event_error_received
|
127
|
+
:error_received => :event_error_received
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
def action_message_received(message)
|
132
132
|
if message.kind_of? Manager::ManagerInterfaceEvent
|
133
133
|
# Trigger the return value of the waiting action id...
|
134
134
|
corresponding_action = @current_action_with_causal_events
|
135
135
|
event_collection = @event_collection_for_current_action
|
136
|
-
|
136
|
+
|
137
137
|
if corresponding_action
|
138
|
-
|
138
|
+
|
139
139
|
# If this is the meta-event which signals no more events will follow and the response is complete.
|
140
140
|
if message.name.downcase == corresponding_action.causal_event_terminator_name
|
141
|
-
|
141
|
+
|
142
142
|
# Result found! Wake up any Threads waiting
|
143
143
|
corresponding_action.future_resource.resource = event_collection.freeze
|
144
|
-
|
144
|
+
|
145
145
|
@current_action_with_causal_events = nil
|
146
146
|
@event_collection_for_current_action = nil
|
147
|
-
|
147
|
+
|
148
148
|
else
|
149
149
|
event_collection << message
|
150
150
|
# We have more causal events coming.
|
@@ -152,7 +152,7 @@ module Adhearsion
|
|
152
152
|
else
|
153
153
|
ahn_log.ami.error "Got an unexpected event on actions socket! This may be a bug! #{message.inspect}"
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
elsif message["ActionID"].nil?
|
157
157
|
# No ActionID! Release the write lock and wake up the waiter
|
158
158
|
else
|
@@ -160,7 +160,7 @@ module Adhearsion
|
|
160
160
|
corresponding_action = data_for_message_received_with_action_id action_id
|
161
161
|
if corresponding_action
|
162
162
|
message.action = corresponding_action
|
163
|
-
|
163
|
+
|
164
164
|
if corresponding_action.has_causal_events?
|
165
165
|
# By this point the write loop will already have started blocking by calling the response() method on the
|
166
166
|
# action. Because we must collect more events before we wake the write loop up again, let's create these
|
@@ -176,10 +176,10 @@ module Adhearsion
|
|
176
176
|
end
|
177
177
|
end
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
def action_error_received(ami_error)
|
181
181
|
action_id = ami_error["ActionID"]
|
182
|
-
|
182
|
+
|
183
183
|
corresponding_action = data_for_message_received_with_action_id action_id
|
184
184
|
|
185
185
|
if corresponding_action
|
@@ -188,7 +188,7 @@ module Adhearsion
|
|
188
188
|
ahn_log.ami.error "Received an AMI error with an unrecognized ActionID!! This may be an bug! #{ami_error.inspect}"
|
189
189
|
end
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
##
|
193
193
|
# Called only when this ManagerInterface is instantiated with events enabled.
|
194
194
|
#
|
@@ -197,22 +197,22 @@ module Adhearsion
|
|
197
197
|
# TODO: convert the event name to a certain namespace.
|
198
198
|
Events.trigger %w[asterisk manager_interface], event
|
199
199
|
end
|
200
|
-
|
200
|
+
|
201
201
|
def event_error_received(message)
|
202
202
|
# Does this ever even occur?
|
203
203
|
ahn_log.ami.error "Hmmm, got an error on the AMI events-only socket! This must be a bug! #{message.inspect}"
|
204
204
|
end
|
205
|
-
|
205
|
+
|
206
206
|
##
|
207
207
|
# Called when our Ragel parser encounters some unexpected syntax from Asterisk. Anytime this is called, it should
|
208
208
|
# be considered a bug in Adhearsion. Note: this same method is called regardless of whether the syntax error
|
209
209
|
# happened on the actions socket or on the events socket.
|
210
210
|
#
|
211
211
|
def syntax_error_encountered(ignored_chunk)
|
212
|
-
ahn_log.ami.error "ADHEARSION'S AMI PARSER ENCOUNTERED A SYNTAX ERROR! " +
|
212
|
+
ahn_log.ami.error "ADHEARSION'S AMI PARSER ENCOUNTERED A SYNTAX ERROR! " +
|
213
213
|
"PLEASE REPORT THIS ON http://bugs.adhearsion.com! OFFENDING TEXT:\n#{ignored_chunk.inspect}"
|
214
214
|
end
|
215
|
-
|
215
|
+
|
216
216
|
##
|
217
217
|
# Must be called after instantiation. Also see ManagerInterface::connect().
|
218
218
|
#
|
@@ -223,35 +223,39 @@ module Adhearsion
|
|
223
223
|
establish_events_connection if @events
|
224
224
|
self
|
225
225
|
end
|
226
|
-
|
226
|
+
|
227
227
|
def actions_connection_established
|
228
228
|
@actions_state = :connected
|
229
229
|
@actions_writer_thread = Thread.new(&method(:write_loop))
|
230
230
|
end
|
231
|
-
|
231
|
+
|
232
232
|
def actions_connection_disconnected
|
233
233
|
@actions_state = :disconnected
|
234
|
+
ahn_log.ami.error "AMI connection for ACTION disconnected !!!"
|
235
|
+
establish_actions_connection
|
234
236
|
end
|
235
|
-
|
237
|
+
|
236
238
|
def events_connection_established
|
237
239
|
@events_state = :connected
|
238
240
|
end
|
239
|
-
|
240
|
-
def
|
241
|
+
|
242
|
+
def events_connection_disconnected
|
241
243
|
@events_state = :disconnected
|
244
|
+
ahn_log.ami.error "AMI connection for EVENT disconnected !!!"
|
245
|
+
establish_events_connection
|
242
246
|
end
|
243
|
-
|
247
|
+
|
244
248
|
def disconnect!
|
245
249
|
# PSEUDO CODE
|
246
250
|
# TODO: Go through all the waiting condition variables and raise an exception
|
247
251
|
#@write_queue << :STOP!
|
248
|
-
raise NotImplementedError
|
252
|
+
#raise NotImplementedError
|
249
253
|
end
|
250
|
-
|
254
|
+
|
251
255
|
def dynamic
|
252
256
|
# TODO: Return an object which responds to method_missing
|
253
257
|
end
|
254
|
-
|
258
|
+
|
255
259
|
##
|
256
260
|
# Used to directly send a new action to Asterisk. Note: NEVER supply an ActionID; these are handled internally.
|
257
261
|
#
|
@@ -269,7 +273,7 @@ module Adhearsion
|
|
269
273
|
raise NotImplementedError
|
270
274
|
end
|
271
275
|
end
|
272
|
-
|
276
|
+
|
273
277
|
##
|
274
278
|
# Sends an action over the AMI connection and blocks your Thread until the response comes in. If there was an error
|
275
279
|
# for some reason, the error will be raised as an ManagerInterfaceError.
|
@@ -284,16 +288,16 @@ module Adhearsion
|
|
284
288
|
raise response if response.kind_of?(ManagerInterfaceError)
|
285
289
|
end
|
286
290
|
end
|
287
|
-
|
291
|
+
|
288
292
|
alias send_action send_action_synchronously
|
289
|
-
|
290
|
-
|
293
|
+
|
294
|
+
|
291
295
|
####### #######
|
292
296
|
########### ###########
|
293
|
-
################# SOON-DEPRECATED COMMANDS #################
|
297
|
+
################# SOON-DEPRECATED COMMANDS #################
|
294
298
|
########### ###########
|
295
299
|
####### #######
|
296
|
-
|
300
|
+
|
297
301
|
# ping sends an action to the Asterisk Manager Interface that returns a pong
|
298
302
|
# more details here: http://www.voip-info.org/wiki/index.php?page=Asterisk+Manager+API+Action+Ping
|
299
303
|
def ping
|
@@ -301,14 +305,14 @@ module Adhearsion
|
|
301
305
|
send_action "Ping"
|
302
306
|
true
|
303
307
|
end
|
304
|
-
|
308
|
+
|
305
309
|
def deprecation_warning
|
306
310
|
ahn_log.ami.deprecation.warn "The implementation of the ping, originate, introduce, hangup, call_into_context " +
|
307
311
|
"and call_and_exec methods will soon be moved from this class to SuperManager. At the moment, the " +
|
308
312
|
"SuperManager abstractions are not completed. Don't worry. The migration to SuperManager will be very easy."+
|
309
313
|
" See http://docs.adhearsion.com/AMI for more information."
|
310
314
|
end
|
311
|
-
|
315
|
+
|
312
316
|
# The originate method launches a call to Asterisk, full details here:
|
313
317
|
# http://www.voip-info.org/tiki-index.php?page=Asterisk+Manager+API+Action+Originate
|
314
318
|
# Takes these arguments as a hash:
|
@@ -324,7 +328,7 @@ module Adhearsion
|
|
324
328
|
# Application: Application to use on connect (use Data for parameters)
|
325
329
|
# Data : Data if Application parameter is used
|
326
330
|
# Async: For the origination to be asynchronous (allows multiple calls to be generated without waiting for a response)
|
327
|
-
# ActionID: The request identifier. It allows you to identify the response to this request.
|
331
|
+
# ActionID: The request identifier. It allows you to identify the response to this request.
|
328
332
|
# You may use a number or a string. Useful when you make several simultaneous requests.
|
329
333
|
#
|
330
334
|
# For example:
|
@@ -375,7 +379,7 @@ module Adhearsion
|
|
375
379
|
originate args
|
376
380
|
end
|
377
381
|
|
378
|
-
# call_into_context is syntactic sugar for the Asterisk originate command that allows you to
|
382
|
+
# call_into_context is syntactic sugar for the Asterisk originate command that allows you to
|
379
383
|
# lanuch a call into a particular context. For example:
|
380
384
|
#
|
381
385
|
# call_into_context('SIP/1000@sipnetworks.com', 'my_context', { :variables => { :session_guid => new_guid }})
|
@@ -386,20 +390,20 @@ module Adhearsion
|
|
386
390
|
args[:exten] = options[:extension] if options[:extension]
|
387
391
|
args[:caller_id] = options[:caller_id] if options[:caller_id]
|
388
392
|
if options[:variables] && options[:variables].kind_of?(Hash)
|
389
|
-
args[:variable] = options[:variables].map {|pair| pair.join('=')}.join(
|
393
|
+
args[:variable] = options[:variables].map {|pair| pair.join('=')}.join(AHN_CONFIG.asterisk.argument_delimiter)
|
390
394
|
end
|
391
395
|
originate args
|
392
396
|
end
|
393
|
-
|
397
|
+
|
394
398
|
####### #######
|
395
399
|
########### ###########
|
396
|
-
################# END SOON-DEPRECATED COMMANDS #################
|
400
|
+
################# END SOON-DEPRECATED COMMANDS #################
|
397
401
|
########### ###########
|
398
402
|
####### #######
|
399
403
|
|
400
|
-
|
404
|
+
|
401
405
|
protected
|
402
|
-
|
406
|
+
|
403
407
|
##
|
404
408
|
# This class will be removed once this AMI library fully supports all known protocol anomalies.
|
405
409
|
#
|
@@ -411,21 +415,21 @@ module Adhearsion
|
|
411
415
|
def initialize(name)
|
412
416
|
super "At the moment this AMI library doesn't support the #{name.inspect} action because it causes a protocol anomaly. Support for it will be coming shortly."
|
413
417
|
end
|
414
|
-
|
418
|
+
|
415
419
|
end
|
416
|
-
|
420
|
+
|
417
421
|
def check_action_name(name)
|
418
422
|
name = name.to_s.downcase
|
419
423
|
raise UnsupportedActionName.new(name) if UnsupportedActionName::UNSUPPORTED_ACTION_NAMES.include? name
|
420
424
|
true
|
421
425
|
end
|
422
|
-
|
426
|
+
|
423
427
|
def write_loop
|
424
428
|
loop do
|
425
429
|
next_action = @write_queue.shift
|
426
430
|
return :stopped if next_action.equal? :STOP!
|
427
431
|
register_action_with_metadata next_action
|
428
|
-
|
432
|
+
|
429
433
|
ahn_log.ami.debug "Sending AMI action: #{"\n>>> " + next_action.to_s.gsub(/(\r\n)+/, "\n>>> ")}"
|
430
434
|
@actions_connection.send_data next_action.to_s
|
431
435
|
# If it's "causal event" action, we must wait here until it's fully responded
|
@@ -434,7 +438,7 @@ module Adhearsion
|
|
434
438
|
rescue => e
|
435
439
|
p e
|
436
440
|
end
|
437
|
-
|
441
|
+
|
438
442
|
##
|
439
443
|
# When we send out an AMI action, we need to track the ActionID and have the other Thread handling the socket IO
|
440
444
|
# notify the sending Thread that a response has been received. This method instantiates a new FutureResource and
|
@@ -451,13 +455,13 @@ module Adhearsion
|
|
451
455
|
@sent_messages[action.action_id] = action
|
452
456
|
end
|
453
457
|
end
|
454
|
-
|
458
|
+
|
455
459
|
def data_for_message_received_with_action_id(action_id)
|
456
460
|
@sent_messages_lock.synchronize do
|
457
461
|
@sent_messages.delete action_id
|
458
462
|
end
|
459
463
|
end
|
460
|
-
|
464
|
+
|
461
465
|
##
|
462
466
|
# Instantiates a new ManagerInterfaceActionsConnection and assigns it to @actions_connection.
|
463
467
|
#
|
@@ -471,14 +475,14 @@ module Adhearsion
|
|
471
475
|
end
|
472
476
|
login_actions
|
473
477
|
end
|
474
|
-
|
478
|
+
|
475
479
|
##
|
476
480
|
# Instantiates a new ManagerInterfaceEventsConnection and assigns it to @events_connection.
|
477
481
|
#
|
478
482
|
# @return [EventSocket]
|
479
483
|
#
|
480
484
|
def establish_events_connection
|
481
|
-
|
485
|
+
|
482
486
|
# Note: the @events_connection instance variable is set in login()
|
483
487
|
@events_connection = EventSocket.connect(@host, @port) do |handler|
|
484
488
|
handler.receive_data { |data| @events_lexer << data }
|
@@ -499,7 +503,7 @@ module Adhearsion
|
|
499
503
|
response
|
500
504
|
end
|
501
505
|
end
|
502
|
-
|
506
|
+
|
503
507
|
##
|
504
508
|
# Since this method is always called after the login_actions method, an AuthenticationFailedException would have already
|
505
509
|
# been raised if the username/password were off. Because this is the only action we ever need to send on this socket,
|
@@ -509,7 +513,7 @@ module Adhearsion
|
|
509
513
|
login_action = ManagerInterfaceAction.new "Login", "Username" => @username, "Secret" => @password, "Events" => "On"
|
510
514
|
@events_connection.send_data login_action.to_s
|
511
515
|
end
|
512
|
-
|
516
|
+
|
513
517
|
def parse_options(options)
|
514
518
|
unrecognized_keys = options.keys.map { |key| key.to_sym } - DEFAULT_SETTINGS.keys
|
515
519
|
if unrecognized_keys.any?
|
@@ -517,19 +521,19 @@ module Adhearsion
|
|
517
521
|
end
|
518
522
|
DEFAULT_SETTINGS.merge options
|
519
523
|
end
|
520
|
-
|
524
|
+
|
521
525
|
##
|
522
526
|
# Raised when calling ManagerInterface#connect!() and the server responds with an error after logging in.
|
523
527
|
#
|
524
528
|
class AuthenticationFailedException < Exception; end
|
525
|
-
|
529
|
+
|
526
530
|
class NotConnectedError < Exception; end
|
527
|
-
|
531
|
+
|
528
532
|
##
|
529
533
|
# Each time ManagerInterface#send_action is invoked, a new ManagerInterfaceAction is instantiated.
|
530
534
|
#
|
531
535
|
class ManagerInterfaceAction
|
532
|
-
|
536
|
+
|
533
537
|
attr_reader :name, :headers, :future_resource, :action_id, :causal_event_terminator_name
|
534
538
|
def initialize(name, headers={})
|
535
539
|
@name = name.to_s.downcase.freeze
|
@@ -538,7 +542,7 @@ module Adhearsion
|
|
538
542
|
@future_resource = FutureResource.new
|
539
543
|
@causal_event_terminator_name = ManagerInterface.causal_event_terminator_name_for name
|
540
544
|
end
|
541
|
-
|
545
|
+
|
542
546
|
##
|
543
547
|
# Used internally by ManagerInterface for the actions in AMI which break the protocol's definition and do not
|
544
548
|
# reply with an ActionID.
|
@@ -546,7 +550,7 @@ module Adhearsion
|
|
546
550
|
def replies_with_action_id?
|
547
551
|
ManagerInterface.replies_with_action_id?(@name, @headers)
|
548
552
|
end
|
549
|
-
|
553
|
+
|
550
554
|
##
|
551
555
|
# Some AMI actions effectively respond with many events which collectively constitute the actual response. These
|
552
556
|
# Must be handled specially by the protocol parser, so this method helps inform the parser.
|
@@ -554,7 +558,7 @@ module Adhearsion
|
|
554
558
|
def has_causal_events?
|
555
559
|
ManagerInterface.has_causal_events?(@name, @headers)
|
556
560
|
end
|
557
|
-
|
561
|
+
|
558
562
|
##
|
559
563
|
# Abstracts the generation of new ActionIDs. This could be implemented virutally any way, provided each
|
560
564
|
# invocation returns something unique, so this will generate a GUID and return it.
|
@@ -564,7 +568,7 @@ module Adhearsion
|
|
564
568
|
def new_action_id
|
565
569
|
new_guid # Implemented in lib/adhearsion/foundation/pseudo_guid.rb
|
566
570
|
end
|
567
|
-
|
571
|
+
|
568
572
|
##
|
569
573
|
# Converts this action into a protocol-valid String, ready to be sent over a socket.
|
570
574
|
#
|
@@ -575,7 +579,7 @@ module Adhearsion
|
|
575
579
|
(@headers.any? ? "\r\n\r\n" : "\r\n")
|
576
580
|
)
|
577
581
|
end
|
578
|
-
|
582
|
+
|
579
583
|
##
|
580
584
|
# If the response has simply not been received yet from Asterisk, the calling Thread will block until it comes
|
581
585
|
# in. Once the response comes in, subsequent calls immediately return a reference to the ManagerInterfaceResponse
|
@@ -584,7 +588,7 @@ module Adhearsion
|
|
584
588
|
def response
|
585
589
|
future_resource.resource
|
586
590
|
end
|
587
|
-
|
591
|
+
|
588
592
|
end
|
589
593
|
end
|
590
594
|
end
|