adhearsion 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +35 -3
- data/Gemfile +3 -0
- data/Rakefile +23 -19
- data/adhearsion.gemspec +133 -133
- data/app_generators/ahn/ahn_generator.rb +1 -0
- data/app_generators/ahn/templates/Gemfile +7 -0
- data/app_generators/ahn/templates/Rakefile +4 -2
- data/app_generators/ahn/templates/config/startup.rb +5 -14
- data/bin/ahn +1 -0
- data/bin/jahn +1 -0
- data/lib/adhearsion.rb +1 -0
- data/lib/adhearsion/cli.rb +70 -19
- data/lib/adhearsion/foundation/blank_slate.rb +2 -2
- data/lib/adhearsion/foundation/event_socket.rb +1 -0
- data/lib/adhearsion/initializer/configuration.rb +2 -2
- data/lib/adhearsion/version.rb +1 -1
- data/lib/adhearsion/voip/asterisk/commands.rb +107 -36
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +3 -2
- data/lib/adhearsion/voip/asterisk/config_manager.rb +1 -1
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +3 -3
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +13 -12
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +1 -0
- data/lib/adhearsion/voip/call.rb +2 -1
- data/lib/adhearsion/voip/dial_plan.rb +5 -1
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +2 -2
- data/lib/adhearsion/voip/dsl/numerical_string.rb +16 -3
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +1 -1
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +0 -1
- data/lib/theatre/callback_definition_loader.rb +2 -2
- metadata +60 -38
@@ -49,6 +49,7 @@ class AhnGenerator < RubiGen::Base
|
|
49
49
|
m.file *["events.rb"]*2
|
50
50
|
m.file *["README"]*2
|
51
51
|
m.file *["Rakefile"]*2
|
52
|
+
m.file *["Gemfile"]*2
|
52
53
|
|
53
54
|
# m.dependency "install_rubigen_scripts", [destination_root, 'ahn', 'adhearsion', 'test_spec'],
|
54
55
|
# :shebang => options[:shebang], :collision => :force
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# This file is for the "rake" tool which automates project-related tasks. If you need to automate things, you can create
|
2
2
|
# a new Rake task here. See http://rake.rubyforge.org for more info.
|
3
3
|
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.setup
|
6
|
+
Bundler.require
|
4
7
|
|
5
8
|
begin
|
6
|
-
require 'adhearsion'
|
7
9
|
require 'adhearsion/tasks'
|
8
10
|
rescue LoadError
|
9
11
|
STDERR.puts "\nCannot load Adhearsion! Not all Rake tasks will be loaded!\n\n"
|
@@ -22,4 +24,4 @@ task :gitignore do
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
25
|
-
end
|
27
|
+
end
|
@@ -1,16 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
# config/startup.rb directly and have a local checkout of Adhearsion in your
|
6
|
-
# application directory.
|
7
|
-
require File.dirname(__FILE__) + "/../adhearsion/lib/adhearsion.rb"
|
8
|
-
else
|
9
|
-
require 'rubygems'
|
10
|
-
gem 'adhearsion', '>= 0.8.2'
|
11
|
-
require 'adhearsion'
|
12
|
-
end
|
13
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.setup
|
4
|
+
Bundler.require
|
14
5
|
|
15
6
|
Adhearsion::Configuration.configure do |config|
|
16
7
|
|
@@ -71,7 +62,7 @@ Adhearsion::Configuration.configure do |config|
|
|
71
62
|
# :password => 'password12345',
|
72
63
|
# :allow_anonymous => false,
|
73
64
|
# :try_sasl => false
|
74
|
-
|
65
|
+
|
75
66
|
# Configure XMPP call controller
|
76
67
|
# config.enable_xmpp :jid => 'active-calls.xmpp.example.com',
|
77
68
|
# :password => 'passwd',
|
data/bin/ahn
CHANGED
data/bin/jahn
CHANGED
data/lib/adhearsion.rb
CHANGED
data/lib/adhearsion/cli.rb
CHANGED
@@ -14,23 +14,24 @@ Usage:
|
|
14
14
|
ahn disable component COMPONENT_NAME
|
15
15
|
ahn create component COMPONENT_NAME
|
16
16
|
USAGE
|
17
|
+
class << self
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
def execute!
|
20
|
+
CommandHandler.send(*parse_arguments)
|
21
|
+
rescue CommandHandler::CLIException => error
|
22
|
+
fail_and_print_usage error
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
##
|
26
|
+
# Provides a small abstraction of Kernel::abort().
|
27
|
+
#
|
28
|
+
def fail_and_print_usage(error)
|
29
|
+
Kernel.abort "#{error.message}\n\n#{USAGE}"
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
def parse_arguments(args=ARGV.clone)
|
33
|
+
action = args.shift
|
34
|
+
case action
|
34
35
|
when /^-?-?h(elp)?$/, nil then [:help]
|
35
36
|
when /^-?-?v(ersion)?$/ then [:version]
|
36
37
|
when "create"
|
@@ -67,6 +68,7 @@ USAGE
|
|
67
68
|
end
|
68
69
|
else
|
69
70
|
[action, *args]
|
71
|
+
end
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -102,23 +104,72 @@ USAGE
|
|
102
104
|
|
103
105
|
app_path = PathString.from_application_subdirectory Dir.pwd
|
104
106
|
|
105
|
-
|
107
|
+
if app_path.nil?
|
108
|
+
new_component_dir = File.join Dir.pwd, component_name
|
109
|
+
else
|
110
|
+
puts "Adhearsion application detected. Creating new component at components/#{component_name}"
|
111
|
+
new_component_dir = File.join app_path, "components", component_name
|
112
|
+
end
|
106
113
|
|
107
|
-
new_component_dir = app_path + "/components/#{component_name}"
|
108
114
|
raise ComponentError.new("Component #{component_name} already exists!") if File.exists?(new_component_dir)
|
109
115
|
|
110
116
|
# Everything's good. Let's create the component
|
111
117
|
Dir.mkdir new_component_dir
|
112
|
-
|
118
|
+
|
119
|
+
# Initial component code file
|
120
|
+
Dir.mkdir File.join(new_component_dir, "lib")
|
121
|
+
fn = File.join("lib", "#{component_name}.rb")
|
122
|
+
puts "- #{fn}: Initial component code file"
|
123
|
+
File.open(File.join(new_component_dir, fn),"w") do |file|
|
113
124
|
file.puts <<-RUBY
|
114
125
|
# See http://docs.adhearsion.com for more information on how to write components or
|
115
126
|
# look at the examples in newly-created projects.
|
116
127
|
RUBY
|
117
128
|
end
|
118
|
-
|
129
|
+
|
130
|
+
# Component configuration
|
131
|
+
Dir.mkdir File.join(new_component_dir, "config")
|
132
|
+
fn = File.join("config", "#{component_name}.yml")
|
133
|
+
puts "- #{fn}: Example component configuration YAML"
|
134
|
+
File.open(File.join(new_component_dir, fn),"w") do |file|
|
119
135
|
file.puts '# You can use this file for component-specific configuration.'
|
120
136
|
end
|
121
|
-
|
137
|
+
|
138
|
+
# Component example gemspec
|
139
|
+
fn = File.join("#{component_name}.gemspec")
|
140
|
+
puts "- #{fn}: Example component gemspec"
|
141
|
+
File.open(File.join(new_component_dir, fn), "w") do |file|
|
142
|
+
file.puts <<-RUBY
|
143
|
+
GEM_FILES = %w{
|
144
|
+
#{component_name}.gemspec
|
145
|
+
lib/#{component_name}.rb
|
146
|
+
config/#{component_name}.yml
|
147
|
+
}
|
148
|
+
|
149
|
+
Gem::Specification.new do |s|
|
150
|
+
s.name = "#{component_name}"
|
151
|
+
s.version = "0.0.1"
|
152
|
+
|
153
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
154
|
+
s.authors = ["Your Name Here!"]
|
155
|
+
|
156
|
+
s.date = Date.today.to_s
|
157
|
+
s.description = "This Adhearsion component gem has not yet been described."
|
158
|
+
s.email = "noreply@example.com"
|
159
|
+
|
160
|
+
s.files = GEM_FILES
|
161
|
+
|
162
|
+
s.has_rdoc = false
|
163
|
+
s.homepage = "http://adhearsion.com"
|
164
|
+
s.require_paths = ["lib"]
|
165
|
+
s.rubygems_version = "1.2.0"
|
166
|
+
s.summary = "This Adhearsion component gem has no summary."
|
167
|
+
|
168
|
+
s.specification_version = 2
|
169
|
+
end
|
170
|
+
RUBY
|
171
|
+
end
|
172
|
+
puts "Created blank component '#{component_name}' at #{new_component_dir}"
|
122
173
|
else
|
123
174
|
raise CommandHandler::UnknownCommand.new("Provided too many arguments to 'create'")
|
124
175
|
end
|
@@ -1,3 +1,3 @@
|
|
1
1
|
class BlankSlate
|
2
|
-
(instance_methods -
|
3
|
-
end
|
2
|
+
(instance_methods.map{|m| m.to_sym} - [:instance_eval, :object_id]).each { |m| undef_method m unless m.to_s =~ /^__/ }
|
3
|
+
end
|
@@ -167,6 +167,7 @@ class EventSocket
|
|
167
167
|
def new_handler_from_block(&handler_block)
|
168
168
|
handler = Object.new
|
169
169
|
handler.metaclass.send :attr_accessor, :set_callbacks
|
170
|
+
handler.metaclass.send :public, :set_callbacks, :set_callbacks=
|
170
171
|
handler.set_callbacks = {:receive_data => false, :disconnected => false, :connected => false }
|
171
172
|
|
172
173
|
def handler.receive_data(&block)
|
@@ -246,8 +246,8 @@ module Adhearsion
|
|
246
246
|
|
247
247
|
unless acl
|
248
248
|
self.acl = []
|
249
|
-
overrides[ :deny].
|
250
|
-
overrides[:allow].
|
249
|
+
[*overrides[ :deny]].compact.each { |ip| acl << 'deny' << ip }
|
250
|
+
[*overrides[:allow]].compact.each { |ip| acl << 'allow' << ip }
|
251
251
|
acl.concat %w[allow 127.0.0.1] if acl.empty?
|
252
252
|
end
|
253
253
|
end
|
data/lib/adhearsion/version.rb
CHANGED
@@ -36,7 +36,7 @@ module Adhearsion
|
|
36
36
|
variable "TRANSFER_CONTEXT" => options[:context] if options && options.has_key?(:context)
|
37
37
|
extend_dynamic_features_with "atxfer"
|
38
38
|
end,
|
39
|
-
:blind_transfer => lambda do
|
39
|
+
:blind_transfer => lambda do |options|
|
40
40
|
variable "TRANSFER_CONTEXT" => options[:context] if options && options.has_key?(:context)
|
41
41
|
extend_dynamic_features_with 'blindxfer'
|
42
42
|
end
|
@@ -174,7 +174,9 @@ module Adhearsion
|
|
174
174
|
# Plays the specified sound file names. This method will handle Time/DateTime objects (e.g. Time.now),
|
175
175
|
# Fixnums (e.g. 1000), Strings which are valid Fixnums (e.g "123"), and direct sound files. When playing
|
176
176
|
# numbers, Adhearsion assumes you're saying the number, not the digits. For example, play("100")
|
177
|
-
# is pronounced as "one hundred" instead of "one zero zero".
|
177
|
+
# is pronounced as "one hundred" instead of "one zero zero". To specify how the Date/Time objects are said
|
178
|
+
# pass in as an array with the first parameter as the Date/Time/DateTime object along with a hash with the
|
179
|
+
# additional options. See play_time for more information.
|
178
180
|
#
|
179
181
|
# Note: it is not necessary to supply a sound file extension; Asterisk will try to find a sound
|
180
182
|
# file encoded using the current channel's codec, if one exists. If not, it will transcode from
|
@@ -184,13 +186,17 @@ module Adhearsion
|
|
184
186
|
# play 'hello-world'
|
185
187
|
# @example Speak current time
|
186
188
|
# play Time.now
|
189
|
+
# @example Speak today's date
|
190
|
+
# play Date.today
|
191
|
+
# @example Speak today's date in a specific format
|
192
|
+
# play [Date.today, {:format => 'BdY'}]
|
187
193
|
# @example Play sound file, speak number, play two more sound files
|
188
194
|
# play %w"a-connect-charge-of 22 cents-per-minute will-apply"
|
189
195
|
# @example Play two sound files
|
190
196
|
# play "you-sound-cute", "what-are-you-wearing"
|
191
197
|
#
|
192
198
|
def play(*arguments)
|
193
|
-
arguments.
|
199
|
+
arguments.each do |argument|
|
194
200
|
play_time(argument) || play_numeric(argument) || play_string(argument)
|
195
201
|
end
|
196
202
|
end
|
@@ -911,6 +917,62 @@ module Adhearsion
|
|
911
917
|
nil
|
912
918
|
end
|
913
919
|
|
920
|
+
##
|
921
|
+
# Executes the SayPhonetic command. This command will read the text passed in
|
922
|
+
# out load using the NATO phonetic alphabet.
|
923
|
+
#
|
924
|
+
# @param [String] Passed in as the text to read aloud
|
925
|
+
#
|
926
|
+
# @see http://www.voip-info.org/wiki/view/Asterisk+cmd+SayPhonetic Asterisk SayPhonetic Command
|
927
|
+
def say_phonetic(text)
|
928
|
+
execute "sayphonetic", text
|
929
|
+
end
|
930
|
+
|
931
|
+
##
|
932
|
+
# Executes the SayAlpha command. This command will read the text passed in
|
933
|
+
# out loud, character-by-character.
|
934
|
+
#
|
935
|
+
# @param [String] Passed in as the text to read aloud
|
936
|
+
#
|
937
|
+
# @example Say "one a two dot pound"
|
938
|
+
# say_chars "1a2.#"
|
939
|
+
#
|
940
|
+
# @see http://www.voip-info.org/wiki/view/Asterisk+cmd+SayAlpha Asterisk SayPhonetic Command
|
941
|
+
def say_chars(text)
|
942
|
+
execute "sayalpha", text
|
943
|
+
end
|
944
|
+
|
945
|
+
# Plays the given Date, Time, or Integer (seconds since epoch)
|
946
|
+
# using the given timezone and format.
|
947
|
+
#
|
948
|
+
# @param [Date|Time|DateTime] Time to be said.
|
949
|
+
# @param [Hash] Additional options to specify how exactly to say time specified.
|
950
|
+
#
|
951
|
+
# +:timezone+ - Sends a timezone to asterisk. See /usr/share/zoneinfo for a list. Defaults to the machine timezone.
|
952
|
+
# +:format+ - This is the format the time is to be said in. Defaults to "ABdY 'digits/at' IMp"
|
953
|
+
#
|
954
|
+
# @see http://www.voip-info.org/wiki/view/Asterisk+cmd+SayUnixTime
|
955
|
+
def play_time(*args)
|
956
|
+
argument, options = args.flatten
|
957
|
+
options ||= {}
|
958
|
+
|
959
|
+
timezone = options.delete(:timezone) || ''
|
960
|
+
format = options.delete(:format) || ''
|
961
|
+
epoch = case argument.class.to_s
|
962
|
+
when 'Time' then argument.to_i
|
963
|
+
when 'DateTime' then argument.to_i
|
964
|
+
when 'Date'
|
965
|
+
format = 'BdY' unless format.present?
|
966
|
+
argument.to_time.to_i
|
967
|
+
else
|
968
|
+
nil
|
969
|
+
end
|
970
|
+
|
971
|
+
return false if epoch.nil?
|
972
|
+
|
973
|
+
execute(:sayunixtime, epoch, timezone, format)
|
974
|
+
end
|
975
|
+
|
914
976
|
protected
|
915
977
|
|
916
978
|
# wait_for_digits waits for the input of digits based on the number of milliseconds
|
@@ -929,10 +991,10 @@ module Adhearsion
|
|
929
991
|
end
|
930
992
|
|
931
993
|
# allows setting of the callerid number of the call
|
932
|
-
def set_caller_id_number(
|
933
|
-
return unless
|
934
|
-
raise ArgumentError, "Caller ID must be
|
935
|
-
|
994
|
+
def set_caller_id_number(caller_id_num)
|
995
|
+
return unless caller_id_num
|
996
|
+
raise ArgumentError, "Caller ID must be numeric" if caller_id_num.to_s !~ /^\d+$/
|
997
|
+
variable "CALLERID(num)" => caller_id_num
|
936
998
|
end
|
937
999
|
|
938
1000
|
# allows the setting of the callerid name of the call
|
@@ -1016,11 +1078,6 @@ module Adhearsion
|
|
1016
1078
|
dial_status ? dial_status.downcase.to_sym : :cancelled
|
1017
1079
|
end
|
1018
1080
|
|
1019
|
-
def play_time(argument)
|
1020
|
-
if argument.kind_of? Time
|
1021
|
-
execute(:sayunixtime, argument.to_i)
|
1022
|
-
end
|
1023
|
-
end
|
1024
1081
|
|
1025
1082
|
def play_numeric(argument)
|
1026
1083
|
if argument.kind_of?(Numeric) || argument =~ /^\d+$/
|
@@ -1118,6 +1175,7 @@ module Adhearsion
|
|
1118
1175
|
ring_style = options.delete :play
|
1119
1176
|
allow_hangup = options.delete :allow_hangup
|
1120
1177
|
allow_transfer = options.delete :allow_transfer
|
1178
|
+
agi = options.delete :agi
|
1121
1179
|
|
1122
1180
|
raise ArgumentError, "Unrecognized args to join!: #{options.inspect}" if options.any?
|
1123
1181
|
|
@@ -1146,7 +1204,7 @@ module Adhearsion
|
|
1146
1204
|
|
1147
1205
|
terse_character_options = ring_style + allow_transfer + allow_hangup
|
1148
1206
|
|
1149
|
-
[terse_character_options, '', announcement, timeout].map(&:to_s)
|
1207
|
+
[terse_character_options, '', announcement, timeout, agi].map(&:to_s)
|
1150
1208
|
end
|
1151
1209
|
|
1152
1210
|
end
|
@@ -1165,6 +1223,7 @@ module Adhearsion
|
|
1165
1223
|
# :announce - A sound file to play instead of the normal queue announcement.
|
1166
1224
|
# :allow_transfer - Can be :caller, :agent, or :everyone. Allow someone to transfer the call.
|
1167
1225
|
# :allow_hangup - Can be :caller, :agent, or :everyone. Allow someone to hangup with the * key.
|
1226
|
+
# :agi - An AGI script to be called on the calling parties channel just before being connected.
|
1168
1227
|
#
|
1169
1228
|
# @example
|
1170
1229
|
# queue('sales').join!
|
@@ -1187,6 +1246,8 @@ module Adhearsion
|
|
1187
1246
|
# @example
|
1188
1247
|
# queue('sales').join! :allow_hangup => :everyone
|
1189
1248
|
# @example
|
1249
|
+
# queue('sales').join! :agi => 'agi://localhost/sales_queue_callback'
|
1250
|
+
# @example
|
1190
1251
|
# queue('sales').join! :allow_transfer => :agent, :timeout => 30.seconds,
|
1191
1252
|
def join!(options={})
|
1192
1253
|
environment.execute("queue", name, *self.class.format_join_hash_key_arguments(options))
|
@@ -1240,23 +1301,24 @@ module Adhearsion
|
|
1240
1301
|
#
|
1241
1302
|
# According to http://www.voip-info.org/wiki/view/Asterisk+cmd+Queue
|
1242
1303
|
# possible values are:
|
1243
|
-
# TIMEOUT (:timeout
|
1244
|
-
# FULL (:full)
|
1245
|
-
# JOINEMPTY (:joinempty)
|
1246
|
-
# LEAVEEMPTY (:leaveempty)
|
1247
|
-
# JOINUNAVAIL (:joinunavail)
|
1248
|
-
# LEAVEUNAVAIL (:leaveunavail)
|
1249
1304
|
#
|
1250
|
-
#
|
1305
|
+
# TIMEOUT => :timeout
|
1306
|
+
# FULL => :full
|
1307
|
+
# JOINEMPTY => :joinempty
|
1308
|
+
# LEAVEEMPTY => :leaveempty
|
1309
|
+
# JOINUNAVAIL => :joinunavail
|
1310
|
+
# LEAVEUNAVAIL => :leaveunavail
|
1311
|
+
# CONTINUE => :continue
|
1312
|
+
#
|
1313
|
+
# If the QUEUESTATUS variable is not set the call was successfully connected,
|
1314
|
+
# and Adhearsion will return :completed.
|
1251
1315
|
#
|
1252
1316
|
# @param [String] QUEUESTATUS variable from Asterisk
|
1253
1317
|
# @return [Symbol] Symbolized version of QUEUESTATUS
|
1254
1318
|
# @raise QueueDoesNotExistError
|
1255
1319
|
def normalize_queue_status_variable(variable)
|
1256
|
-
variable = "
|
1257
|
-
variable.downcase.to_sym
|
1258
|
-
raise QueueDoesNotExistError.new(name) if queue_status == :unknown
|
1259
|
-
end
|
1320
|
+
variable = "COMPLETED" if variable.nil?
|
1321
|
+
variable.downcase.to_sym
|
1260
1322
|
end
|
1261
1323
|
|
1262
1324
|
class QueueAgentsListProxy
|
@@ -1285,26 +1347,35 @@ module Adhearsion
|
|
1285
1347
|
def new(*args)
|
1286
1348
|
|
1287
1349
|
options = args.last.kind_of?(Hash) ? args.pop : {}
|
1288
|
-
interface = args.shift
|
1350
|
+
interface = args.shift
|
1289
1351
|
|
1352
|
+
raise ArgumentError, "You must specify an interface to add." if interface.nil?
|
1290
1353
|
raise ArgumentError, "You may only supply an interface and a Hash argument!" if args.any?
|
1291
1354
|
|
1292
|
-
penalty
|
1293
|
-
name
|
1355
|
+
penalty = options.delete(:penalty) || ''
|
1356
|
+
name = options.delete(:name) || ''
|
1357
|
+
state_interface = options.delete(:state_interface) || ''
|
1294
1358
|
|
1295
1359
|
raise ArgumentError, "Unrecognized argument(s): #{options.inspect}" if options.any?
|
1296
1360
|
|
1297
|
-
proxy.environment.execute("AddQueueMember", proxy.name, interface, penalty, '', name)
|
1361
|
+
proxy.environment.execute("AddQueueMember", proxy.name, interface, penalty, '', name, state_interface)
|
1298
1362
|
|
1299
|
-
case proxy.environment.variable("AQMSTATUS")
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1363
|
+
added = case proxy.environment.variable("AQMSTATUS")
|
1364
|
+
when "ADDED" then true
|
1365
|
+
when "MEMBERALREADY" then false
|
1366
|
+
when "NOSUCHQUEUE" then raise QueueDoesNotExistError.new(proxy.name)
|
1367
|
+
else
|
1368
|
+
raise "UNRECOGNIZED AQMSTATUS VALUE!"
|
1369
|
+
end
|
1306
1370
|
|
1307
|
-
|
1371
|
+
if added
|
1372
|
+
check_agent_cache!
|
1373
|
+
AgentProxy.new(interface, proxy).tap do |agent_proxy|
|
1374
|
+
@agents << agent_proxy
|
1375
|
+
end
|
1376
|
+
else
|
1377
|
+
false
|
1378
|
+
end
|
1308
1379
|
end
|
1309
1380
|
|
1310
1381
|
# Logs a pre-defined agent into this queue and waits for calls. Pass in :silent => true to stop
|