adhearsion 0.8.4 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. data/CHANGELOG +12 -0
  2. data/Rakefile +6 -5
  3. data/adhearsion.gemspec +9 -5
  4. data/app_generators/ahn/ahn_generator.rb +5 -0
  5. data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb +1 -1
  6. data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +1 -1
  7. data/app_generators/ahn/templates/components/disabled/xmpp_gateway/README.markdown +3 -0
  8. data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +11 -0
  9. data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
  10. data/app_generators/ahn/templates/config/startup.rb +10 -1
  11. data/lib/adhearsion/cli.rb +7 -2
  12. data/lib/adhearsion/foundation/event_socket.rb +1 -1
  13. data/lib/adhearsion/foundation/future_resource.rb +1 -1
  14. data/lib/adhearsion/host_definitions.rb +1 -1
  15. data/lib/adhearsion/initializer.rb +21 -8
  16. data/lib/adhearsion/initializer/configuration.rb +44 -3
  17. data/lib/adhearsion/initializer/database.rb +11 -1
  18. data/lib/adhearsion/initializer/ldap.rb +7 -1
  19. data/lib/adhearsion/initializer/xmpp.rb +42 -0
  20. data/lib/adhearsion/version.rb +26 -2
  21. data/lib/adhearsion/voip/asterisk/agi_server.rb +2 -1
  22. data/lib/adhearsion/voip/asterisk/commands.rb +186 -85
  23. data/lib/adhearsion/voip/asterisk/manager_interface.rb +147 -50
  24. data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1 -1
  25. data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +1 -1
  26. data/lib/adhearsion/voip/call.rb +15 -8
  27. data/lib/adhearsion/voip/dial_plan.rb +21 -4
  28. data/lib/adhearsion/voip/dsl/dialing_dsl.rb +1 -1
  29. data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +2 -2
  30. data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +2 -2
  31. data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +2 -2
  32. data/lib/adhearsion/xmpp/connection.rb +61 -0
  33. data/lib/theatre/invocation.rb +1 -1
  34. data/lib/theatre/namespace_manager.rb +1 -1
  35. metadata +12 -6
  36. data/lib/adhearsion/foundation/global.rb +0 -1
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ 0.8.5
2
+ - Added XMPP module and sample component. This allows you to easily write components which utilise a persistent XMPP connection maintained by Adhearsion
3
+ - Prefer finding the dialplan.rb entry point by the AGI request URI instead of the calling context
4
+ - Added :use_static_conf option for "meetme" to allow the use of disk-file-managed conferences
5
+ - Logging object now shared with ActiveRecord and Blather
6
+ - Fixed a longstanding bug where newlines were not sent after each AGI command
7
+ - Fixed parsing of DBGet AMI command/response
8
+ - Better shutdown handling/cleanup
9
+ - Attempt to allow the AMI socket to reconnect if connection is lost
10
+ - Improved support for Ruby 1.9
11
+ - Numerous smaller bugs fixed. See: https://adhearsion.lighthouseapp.com/projects/5871-adhearsion/milestones/76510-085
12
+
1
13
  0.8.4
2
14
  - Add configurable argument delimiter for talking to Asterisk. This enables Adhearsion to support Asterisk versions 1.4 (and prior) as well as 1.6 (and later).
3
15
  - Fixed using ActiveRecord in Adhearsion components
data/Rakefile CHANGED
@@ -3,6 +3,7 @@ ENV['RUBY_FLAGS'] = "-I#{%w(lib ext bin test).join(File::PATH_SEPARATOR)}"
3
3
 
4
4
  require 'rubygems'
5
5
  require 'rake/gempackagetask'
6
+ require 'rake/testtask'
6
7
 
7
8
  begin
8
9
  require 'spec/rake/spectask'
@@ -45,13 +46,13 @@ Rake::GemPackageTask.new(GEMSPEC).define
45
46
  # # t.options = ['--any', '--extra', '--opts'] # optional
46
47
  # end
47
48
 
48
- desc "Run the unit tests for Adhearsion"
49
- task :spec do
50
- Dir[*AHN_TESTS].each do |file|
51
- load file
52
- end
49
+ Rake::TestTask.new('spec') do |t|
50
+ t.verbose = true
51
+ t.pattern = AHN_TESTS
53
52
  end
54
53
 
54
+ task :default => :spec
55
+
55
56
  desc "Check Ragel version"
56
57
  task :check_ragel_version do
57
58
  ragel_version_match = `ragel --version`.match(/(\d)\.(\d)+/)
@@ -14,6 +14,9 @@ ADHEARSION_FILES = %w{
14
14
  app_generators/ahn/templates/components/disabled/restful_rpc/README.markdown
15
15
  app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb
16
16
  app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb
17
+ app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb
18
+ app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml
19
+ app_generators/ahn/templates/components/disabled/xmpp_gateway/README.markdown
17
20
  app_generators/ahn/templates/components/simon_game/simon_game.rb
18
21
  app_generators/ahn/templates/config/startup.rb
19
22
  app_generators/ahn/templates/dialplan.rb
@@ -38,7 +41,6 @@ ADHEARSION_FILES = %w{
38
41
  lib/adhearsion/foundation/custom_daemonizer.rb
39
42
  lib/adhearsion/foundation/event_socket.rb
40
43
  lib/adhearsion/foundation/future_resource.rb
41
- lib/adhearsion/foundation/global.rb
42
44
  lib/adhearsion/foundation/metaprogramming.rb
43
45
  lib/adhearsion/foundation/numeric.rb
44
46
  lib/adhearsion/foundation/pseudo_guid.rb
@@ -55,6 +57,7 @@ ADHEARSION_FILES = %w{
55
57
  lib/adhearsion/initializer/drb.rb
56
58
  lib/adhearsion/initializer/freeswitch.rb
57
59
  lib/adhearsion/initializer/rails.rb
60
+ lib/adhearsion/initializer/xmpp.rb
58
61
  lib/adhearsion/logging.rb
59
62
  lib/adhearsion/tasks.rb
60
63
  lib/adhearsion/tasks/database.rb
@@ -100,6 +103,7 @@ ADHEARSION_FILES = %w{
100
103
  lib/adhearsion/voip/menu_state_machine/matchers.rb
101
104
  lib/adhearsion/voip/menu_state_machine/menu_builder.rb
102
105
  lib/adhearsion/voip/menu_state_machine/menu_class.rb
106
+ lib/adhearsion/xmpp/connection.rb
103
107
  lib/theatre.rb
104
108
  lib/theatre/callback_definition_loader.rb
105
109
  lib/theatre/guid.rb
@@ -113,14 +117,14 @@ ADHEARSION_FILES = %w{
113
117
 
114
118
  Gem::Specification.new do |s|
115
119
  s.name = "adhearsion"
116
- s.version = "0.8.4"
120
+ s.version = "0.8.5"
117
121
 
118
122
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
119
- s.authors = ["Jay Phillips"]
123
+ s.authors = ["Jay Phillips", "Jason Goecke", "Ben Klang"]
120
124
 
121
- s.date = "2008-08-21"
125
+ s.date = "2010-08-24"
122
126
  s.description = "Adhearsion is an open-source telephony development framework"
123
- s.email = "Jay&Adhearsion.com"
127
+ s.email = "dev&Adhearsion.com"
124
128
  s.executables = ["ahn", "ahnctl", "jahn"]
125
129
 
126
130
  s.files = ADHEARSION_FILES
@@ -27,6 +27,10 @@ class AhnGenerator < RubiGen::Base
27
27
  m.file *["components/simon_game/simon_game.rb"]*2
28
28
  m.file *["components/ami_remote/ami_remote.rb"]*2
29
29
 
30
+ m.file *["components/disabled/xmpp_gateway/xmpp_gateway.rb"]*2
31
+ m.file *["components/disabled/xmpp_gateway/xmpp_gateway.yml"]*2
32
+ m.file *["components/disabled/xmpp_gateway/README.markdown"]*2
33
+
30
34
  m.file *["components/disabled/stomp_gateway/stomp_gateway.rb"]*2
31
35
  m.file *["components/disabled/stomp_gateway/stomp_gateway.yml"]*2
32
36
  m.file *["components/disabled/stomp_gateway/README.markdown"]*2
@@ -83,6 +87,7 @@ EOS
83
87
  BASEDIRS = %w(
84
88
  components/simon_game
85
89
  components/disabled/stomp_gateway
90
+ components/disabled/xmpp_gateway
86
91
  components/disabled/sandbox
87
92
  components/ami_remote
88
93
  components/disabled/restful_rpc/spec
@@ -55,7 +55,7 @@ RESTFUL_API_HANDLER = lambda do |env|
55
55
  rpc_object = Adhearsion::Components.component_manager.extend_object_with(Object.new, :rpc)
56
56
 
57
57
  # TODO: set the content-type and other HTTP headers
58
- response_object = Array rpc_object.send(path, *json)
58
+ response_object = rpc_object.send(path, *json)
59
59
  [200, {"Content-Type" => "application/json"}, response_object.to_json]
60
60
 
61
61
  end
@@ -55,7 +55,7 @@ initialization do
55
55
  next
56
56
  end
57
57
  response.chomp!
58
- case
58
+ case response
59
59
  when "authentication accepted"
60
60
  ahn_log.sandbox "Authentication accepted"
61
61
 
@@ -0,0 +1,3 @@
1
+ In order to use this component, you must have an XMPP connection enabled in config/startup.rb. It is recommended this be done as an XMPP component rather than a standard client.
2
+
3
+ You can use all elements of the Blather DSL scoped to XMPP::Connection
@@ -0,0 +1,11 @@
1
+ initialization do
2
+
3
+ XMPP::Connection.message :body do |m|
4
+ XMPP::Connection.say m.from, "You said: #{m.body}"
5
+ end
6
+
7
+ XMPP::Connection.subscription :request? do |s|
8
+ XMPP::Connection.write_to_stream s.approve!
9
+ end
10
+
11
+ end
@@ -27,7 +27,8 @@ Adhearsion::Configuration.configure do |config|
27
27
  # NOTE: Pay special attention to the argument_delimiter field below:
28
28
  # For Asterisk <= 1.4, use "|" (default)
29
29
  # For Asterisk >= 1.6, use ","
30
- # This setting applies to AMI and AGI
30
+ # The delimiter can also be specified in Asterisk's asterisk.conf.
31
+ # This setting applies only to AGI. The AMI delimiter is auto-detected.
31
32
  config.enable_asterisk :argument_delimiter => '|'
32
33
  # config.asterisk.enable_ami :host => "127.0.0.1", :username => "admin", :password => "password", :events => true
33
34
 
@@ -44,6 +45,8 @@ Adhearsion::Configuration.configure do |config|
44
45
 
45
46
  # Configure a database to use ActiveRecord-backed models. See ActiveRecord::Base.establish_connection
46
47
  # for the appropriate settings here.
48
+ # You can also override the default log destination by supplying an alternate
49
+ # logging object with :logger. The default is ahn_log.db.
47
50
  # config.enable_database :adapter => 'mysql',
48
51
  # :username => 'joe',
49
52
  # :password => 'secret',
@@ -59,6 +62,12 @@ Adhearsion::Configuration.configure do |config|
59
62
  # :password => 'password12345',
60
63
  # :allow_anonymous => false,
61
64
  # :try_sasl => false
65
+
66
+ # Configure XMPP call controller
67
+ # config.enable_xmpp :jid => 'active-calls.xmpp.example.com',
68
+ # :password => 'passwd',
69
+ # :server => 'xmpp.example.com',
70
+ # :port => 5347
62
71
 
63
72
  end
64
73
 
@@ -143,12 +143,17 @@ USAGE
143
143
  app_path = PathString.from_application_subdirectory Dir.pwd
144
144
  if app_path
145
145
  disabled_component_path = File.join app_path, "components", "disabled", name
146
+ disabled_components_path = File.join app_path, "components", "disabled"
146
147
  enabled_component_path = File.join app_path, "components", name
147
148
  if File.directory? disabled_component_path
148
149
  FileUtils.mv disabled_component_path, enabled_component_path
149
150
  puts "Enabled component #{name}"
150
- else
151
+ elsif File.directory? enabled_component_path
152
+ raise ComponentError.new("This component is already enabled.")
153
+ elsif !File.directory? disabled_components_path
151
154
  raise ComponentError.new("There is no components/disabled directory!")
155
+ else
156
+ raise ComponentError.new("The requested component was not found.")
152
157
  end
153
158
  else
154
159
  raise PathInvalid.new(Dir.pwd)
@@ -196,7 +201,7 @@ USAGE
196
201
 
197
202
  end
198
203
 
199
- class CLIException < Exception; end
204
+ class CLIException < StandardError; end
200
205
 
201
206
  class UnknownCommand < CLIException
202
207
  def initialize(cmd)
@@ -198,6 +198,6 @@ class EventSocket
198
198
 
199
199
  end
200
200
 
201
- class ConnectionError < Exception; end
201
+ class ConnectionError < StandardError; end
202
202
 
203
203
  end
@@ -27,7 +27,7 @@ class FutureResource
27
27
  end
28
28
  end
29
29
 
30
- class ResourceAlreadySetException < Exception
30
+ class ResourceAlreadySetException < StandardError
31
31
  def initialize
32
32
  super "Cannot set this resource twice!"
33
33
  end
@@ -57,7 +57,7 @@ module Adhearsion
57
57
  self.class.definitions << self
58
58
  end
59
59
 
60
- class HostDefinitionException < Exception
60
+ class HostDefinitionException < StandardError
61
61
 
62
62
  end
63
63
 
@@ -1,12 +1,22 @@
1
1
  module Adhearsion
2
2
 
3
+ mattr_accessor :status
4
+
3
5
  class << self
4
6
 
5
7
  ##
6
8
  # Shuts down the framework.
7
9
  #
8
10
  def shutdown!
11
+ if self.status == :stopping
12
+ # This is the second shutdown request we've received while attempting
13
+ # to shut down gracefully. At this point, let's pull the plug...
14
+ ahn_log.warning "Shutting down immediately at #{Time.now}"
15
+ exit
16
+ end
9
17
  ahn_log "Shutting down gracefully at #{Time.now}."
18
+ self.status = :stopping
19
+ Events.trigger_immediately :shutdown
10
20
  Events.stop!
11
21
  exit
12
22
  end
@@ -115,7 +125,7 @@ module Adhearsion
115
125
  def initialize(path=nil, options={})
116
126
  @@started = true
117
127
  @path = path
118
- @daemon = options[:daemon]
128
+ @daemon = options[:daemon] || ENV['DAEMON']
119
129
  @pid_file = options[:pid_file].nil? ? ENV['PID_FILE'] : options[:pid_file]
120
130
  @loaded_init_files = options[:loaded_init_files]
121
131
  end
@@ -123,6 +133,8 @@ module Adhearsion
123
133
  def start
124
134
  self.class.ahn_root = path
125
135
 
136
+ Adhearsion.status = :starting
137
+
126
138
  resolve_pid_file_path
127
139
  resolve_log_file_path
128
140
  daemonize! if should_daemonize?
@@ -140,6 +152,7 @@ module Adhearsion
140
152
  init_events_file
141
153
 
142
154
  ahn_log "Adhearsion initialized!"
155
+ Adhearsion.status = :running
143
156
 
144
157
  trigger_after_initialized_hooks
145
158
  join_important_threads
@@ -172,9 +185,7 @@ module Adhearsion
172
185
  def catch_termination_signal
173
186
  %w'INT TERM'.each do |process_signal|
174
187
  trap process_signal do
175
- ahn_log "Shutting down gracefully at #{Time.now}."
176
- Events.trigger_immediately :shutdown
177
- exit
188
+ Adhearsion.shutdown!
178
189
  end
179
190
  end
180
191
  end
@@ -273,11 +284,13 @@ Adhearsion will abort until you fix this. Sorry for the incovenience.
273
284
  require 'adhearsion/initializer/asterisk.rb'
274
285
  require 'adhearsion/initializer/drb.rb'
275
286
  require 'adhearsion/initializer/rails.rb'
287
+ require 'adhearsion/initializer/xmpp.rb'
276
288
  # require 'adhearsion/initializer/freeswitch.rb'
277
289
 
278
290
  AsteriskInitializer.start if AHN_CONFIG.asterisk_enabled?
279
291
  DrbInitializer.start if AHN_CONFIG.drb_enabled?
280
292
  RailsInitializer.start if AHN_CONFIG.rails_enabled?
293
+ XMPPInitializer.start if AHN_CONFIG.xmpp_enabled?
281
294
  # FreeswitchInitializer.start if AHN_CONFIG.freeswitch_enabled?
282
295
 
283
296
  end
@@ -303,7 +316,7 @@ Adhearsion will abort until you fix this. Sorry for the incovenience.
303
316
  end
304
317
 
305
318
  def should_daemonize?
306
- @daemon || ENV['DAEMON']
319
+ @daemon
307
320
  end
308
321
 
309
322
  def daemonize!
@@ -324,8 +337,8 @@ Adhearsion will abort until you fix this. Sorry for the incovenience.
324
337
  Logging::DefaultAdhearsionLogger.redefine_outputters
325
338
  end
326
339
 
327
- def create_pid_file(file = pid_file)
328
- if file
340
+ def create_pid_file
341
+ if pid_file
329
342
  File.open pid_file, 'w' do |file|
330
343
  file.puts Process.pid
331
344
  end
@@ -377,6 +390,6 @@ Adhearsion will abort until you fix this. Sorry for the incovenience.
377
390
  end
378
391
  end
379
392
 
380
- class InitializationFailedError < Exception; end
393
+ class InitializationFailedError < StandardError; end
381
394
  end
382
395
  end
@@ -129,8 +129,8 @@ module Adhearsion
129
129
  end
130
130
 
131
131
  def initialize(overrides = {})
132
- @listening_port = self.class.default_listening_port
133
- @listening_host = self.class.default_listening_host
132
+ @listening_port = overrides.has_key?(:port) ? overrides[:port] : self.class.default_listening_port
133
+ @listening_host = overrides.has_key?(:host) ? overrides[:host] : self.class.default_listening_host
134
134
  super
135
135
  end
136
136
  end
@@ -144,8 +144,10 @@ module Adhearsion
144
144
  4573
145
145
  end
146
146
 
147
+ # Keep Asterisk 1.4 (and prior) as the default to protect upgraders
148
+ # This setting only applies to AGI. AMI delimiters are always
149
+ # auto-detected.
147
150
  def default_argument_delimiter
148
- # Keep Asterisk 1.4 (and prior) as the default to protect upgraders
149
151
  '|'
150
152
  end
151
153
  end
@@ -265,5 +267,44 @@ module Adhearsion
265
267
  end
266
268
  add_configuration_for :Rails
267
269
 
270
+ class XMPPConfiguration < AbstractConfiguration
271
+
272
+ attr_accessor :jid, :password, :server, :port
273
+ def initialize(options)
274
+ jid, password, server, port = check_options options
275
+ @jid = jid
276
+ @password = password
277
+ @server = server
278
+ @port = port
279
+ end
280
+
281
+ class << self
282
+ def default_port
283
+ 5222
284
+ end
285
+ end
286
+
287
+ private
288
+
289
+ def check_options(options)
290
+ options = options.clone
291
+ jid = options.delete :jid
292
+ password = options.delete :password
293
+ server = options.delete :server
294
+ port = options.delete :port
295
+ raise ArgumentError, "Unrecognied argument(s) #{options.keys.to_sentence} in XMPP initializer!" unless options.size.zero?
296
+ raise ArgumentError, "Must supply a :jid argument to the XMPP initializer!" unless jid
297
+ raise ArgumentError, "Must supply a :password argument to the XMPP initializer!" unless password
298
+ if server
299
+ port ||= self.class.default_port
300
+ else
301
+ raise ArgumentError, "Must supply a :server argument as well as :port to the XMPP initializer!" if port
302
+ end
303
+ [jid, password, server, port]
304
+ end
305
+
306
+ end
307
+ add_configuration_for :XMPP
308
+
268
309
  end
269
310
  end
@@ -14,6 +14,10 @@ module Adhearsion
14
14
  # You may need to uncomment the following line for older versions of ActiveRecord
15
15
  # ActiveRecord::Base.allow_concurrency = true
16
16
  establish_connection
17
+ ActiveRecord::Base.logger =
18
+ @@config.connection_options.has_key?(:logger) ?
19
+ @@config.connection_options[:logger] :
20
+ ahn_log.db
17
21
  create_call_hook_for_connection_cleanup
18
22
  end
19
23
 
@@ -30,7 +34,13 @@ module Adhearsion
30
34
  end
31
35
 
32
36
  def require_dependencies
33
- require 'active_record'
37
+ begin
38
+ require 'active_record'
39
+ rescue LoadError
40
+ ahn_log.fatal "Database support requires the \"activerecord\" gem."
41
+ # Silence the abort so we don't get an ugly backtrace
42
+ abort ""
43
+ end
34
44
  end
35
45
 
36
46
  def require_models
@@ -31,7 +31,13 @@ module Adhearsion
31
31
  #end
32
32
 
33
33
  def require_dependencies
34
- require 'active_ldap'
34
+ begin
35
+ require 'active_ldap'
36
+ rescue LoadError
37
+ ahn_log.fatal "LDAP support requires the \"activeldap\" gem."
38
+ # Silence the abort so we don't get an ugly backtrace
39
+ abort ""
40
+ end
35
41
  end
36
42
 
37
43
  def require_models