adhearsion 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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