adhearsion-cw 1.0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +109 -0
- data/EVENTS +11 -0
- data/Gemfile +3 -0
- data/LICENSE +456 -0
- data/Rakefile +134 -0
- data/adhearsion.gemspec +174 -0
- data/app_generators/ahn/USAGE +5 -0
- data/app_generators/ahn/ahn_generator.rb +97 -0
- data/app_generators/ahn/templates/.ahnrc +34 -0
- data/app_generators/ahn/templates/Gemfile +7 -0
- data/app_generators/ahn/templates/README +8 -0
- data/app_generators/ahn/templates/Rakefile +27 -0
- data/app_generators/ahn/templates/components/ami_remote/ami_remote.rb +15 -0
- data/app_generators/ahn/templates/components/disabled/HOW_TO_ENABLE +7 -0
- data/app_generators/ahn/templates/components/disabled/restful_rpc/README.markdown +11 -0
- data/app_generators/ahn/templates/components/disabled/restful_rpc/example-client.rb +48 -0
- data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.rb +91 -0
- data/app_generators/ahn/templates/components/disabled/restful_rpc/restful_rpc.yml +34 -0
- data/app_generators/ahn/templates/components/disabled/restful_rpc/spec/restful_rpc_spec.rb +251 -0
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.rb +104 -0
- data/app_generators/ahn/templates/components/disabled/sandbox/sandbox.yml +2 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/README.markdown +47 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.rb +34 -0
- data/app_generators/ahn/templates/components/disabled/stomp_gateway/stomp_gateway.yml +12 -0
- data/app_generators/ahn/templates/components/disabled/xmpp_gateway/README.markdown +3 -0
- data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.rb +11 -0
- data/app_generators/ahn/templates/components/disabled/xmpp_gateway/xmpp_gateway.yml +0 -0
- data/app_generators/ahn/templates/components/simon_game/simon_game.rb +56 -0
- data/app_generators/ahn/templates/config/startup.rb +74 -0
- data/app_generators/ahn/templates/dialplan.rb +3 -0
- data/app_generators/ahn/templates/events.rb +32 -0
- data/bin/ahn +29 -0
- data/bin/ahnctl +68 -0
- data/bin/jahn +43 -0
- data/examples/asterisk_manager_interface/standalone.rb +51 -0
- data/lib/adhearsion/cli.rb +296 -0
- data/lib/adhearsion/component_manager/component_tester.rb +53 -0
- data/lib/adhearsion/component_manager/spec_framework.rb +18 -0
- data/lib/adhearsion/component_manager.rb +272 -0
- data/lib/adhearsion/events_support.rb +84 -0
- data/lib/adhearsion/foundation/all.rb +15 -0
- data/lib/adhearsion/foundation/blank_slate.rb +3 -0
- data/lib/adhearsion/foundation/custom_daemonizer.rb +45 -0
- data/lib/adhearsion/foundation/event_socket.rb +205 -0
- data/lib/adhearsion/foundation/future_resource.rb +36 -0
- data/lib/adhearsion/foundation/metaprogramming.rb +17 -0
- data/lib/adhearsion/foundation/numeric.rb +13 -0
- data/lib/adhearsion/foundation/pseudo_guid.rb +10 -0
- data/lib/adhearsion/foundation/relationship_properties.rb +42 -0
- data/lib/adhearsion/foundation/string.rb +26 -0
- data/lib/adhearsion/foundation/synchronized_hash.rb +96 -0
- data/lib/adhearsion/foundation/thread_safety.rb +7 -0
- data/lib/adhearsion/host_definitions.rb +67 -0
- data/lib/adhearsion/initializer/asterisk.rb +87 -0
- data/lib/adhearsion/initializer/configuration.rb +321 -0
- data/lib/adhearsion/initializer/database.rb +60 -0
- data/lib/adhearsion/initializer/drb.rb +31 -0
- data/lib/adhearsion/initializer/freeswitch.rb +22 -0
- data/lib/adhearsion/initializer/ldap.rb +57 -0
- data/lib/adhearsion/initializer/rails.rb +41 -0
- data/lib/adhearsion/initializer/xmpp.rb +42 -0
- data/lib/adhearsion/initializer.rb +394 -0
- data/lib/adhearsion/logging.rb +92 -0
- data/lib/adhearsion/tasks/components.rb +32 -0
- data/lib/adhearsion/tasks/database.rb +5 -0
- data/lib/adhearsion/tasks/deprecations.rb +59 -0
- data/lib/adhearsion/tasks/generating.rb +20 -0
- data/lib/adhearsion/tasks/lint.rb +4 -0
- data/lib/adhearsion/tasks/testing.rb +37 -0
- data/lib/adhearsion/tasks.rb +17 -0
- data/lib/adhearsion/version.rb +35 -0
- data/lib/adhearsion/voip/asterisk/agi_server.rb +115 -0
- data/lib/adhearsion/voip/asterisk/commands.rb +1581 -0
- data/lib/adhearsion/voip/asterisk/config_generators/agents.conf.rb +140 -0
- data/lib/adhearsion/voip/asterisk/config_generators/config_generator.rb +102 -0
- data/lib/adhearsion/voip/asterisk/config_generators/queues.conf.rb +250 -0
- data/lib/adhearsion/voip/asterisk/config_generators/voicemail.conf.rb +240 -0
- data/lib/adhearsion/voip/asterisk/config_manager.rb +71 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rb +1681 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_lexer.rl.rb +341 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_messages.rb +78 -0
- data/lib/adhearsion/voip/asterisk/manager_interface/ami_protocol_lexer_machine.rl +87 -0
- data/lib/adhearsion/voip/asterisk/manager_interface.rb +705 -0
- data/lib/adhearsion/voip/asterisk/special_dial_plan_managers.rb +80 -0
- data/lib/adhearsion/voip/asterisk/super_manager.rb +19 -0
- data/lib/adhearsion/voip/asterisk.rb +4 -0
- data/lib/adhearsion/voip/call.rb +498 -0
- data/lib/adhearsion/voip/call_routing.rb +64 -0
- data/lib/adhearsion/voip/commands.rb +9 -0
- data/lib/adhearsion/voip/constants.rb +39 -0
- data/lib/adhearsion/voip/conveniences.rb +18 -0
- data/lib/adhearsion/voip/dial_plan.rb +250 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl/dialing_dsl_monkey_patches.rb +37 -0
- data/lib/adhearsion/voip/dsl/dialing_dsl.rb +151 -0
- data/lib/adhearsion/voip/dsl/dialplan/control_passing_exception.rb +27 -0
- data/lib/adhearsion/voip/dsl/dialplan/dispatcher.rb +124 -0
- data/lib/adhearsion/voip/dsl/dialplan/parser.rb +69 -0
- data/lib/adhearsion/voip/dsl/dialplan/thread_mixin.rb +16 -0
- data/lib/adhearsion/voip/dsl/numerical_string.rb +128 -0
- data/lib/adhearsion/voip/freeswitch/basic_connection_manager.rb +48 -0
- data/lib/adhearsion/voip/freeswitch/event_handler.rb +58 -0
- data/lib/adhearsion/voip/freeswitch/freeswitch_dialplan_command_factory.rb +129 -0
- data/lib/adhearsion/voip/freeswitch/inbound_connection_manager.rb +38 -0
- data/lib/adhearsion/voip/freeswitch/oes_server.rb +195 -0
- data/lib/adhearsion/voip/menu_state_machine/calculated_match.rb +80 -0
- data/lib/adhearsion/voip/menu_state_machine/matchers.rb +123 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_builder.rb +57 -0
- data/lib/adhearsion/voip/menu_state_machine/menu_class.rb +149 -0
- data/lib/adhearsion/xmpp/connection.rb +61 -0
- data/lib/adhearsion.rb +46 -0
- data/lib/theatre/README.markdown +64 -0
- data/lib/theatre/callback_definition_loader.rb +84 -0
- data/lib/theatre/guid.rb +23 -0
- data/lib/theatre/invocation.rb +121 -0
- data/lib/theatre/namespace_manager.rb +153 -0
- data/lib/theatre/version.rb +2 -0
- data/lib/theatre.rb +151 -0
- metadata +323 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
# TODO: Have all of the initializer modules required and then traverse the subclasses, asking them if they're enabled. If they are enabled, then they should do their initialization stuff. Is this really necessary to develop this entirely new system when the components system exists?
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
|
6
|
+
class DatabaseInitializer
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
require_dependencies
|
12
|
+
require_models
|
13
|
+
@@config = Adhearsion::AHN_CONFIG.database
|
14
|
+
# You may need to uncomment the following line for older versions of ActiveRecord
|
15
|
+
# ActiveRecord::Base.allow_concurrency = true
|
16
|
+
establish_connection
|
17
|
+
ActiveRecord::Base.logger =
|
18
|
+
@@config.connection_options.has_key?(:logger) ?
|
19
|
+
@@config.connection_options[:logger] :
|
20
|
+
ahn_log.db
|
21
|
+
create_call_hook_for_connection_cleanup
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
ActiveRecord::Base.remove_connection
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def create_call_hook_for_connection_cleanup
|
31
|
+
Events.register_callback([:asterisk, :before_call]) do
|
32
|
+
ActiveRecord::Base.verify_active_connections!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def require_dependencies
|
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
|
44
|
+
end
|
45
|
+
|
46
|
+
def require_models
|
47
|
+
AHN_CONFIG.files_from_setting("paths", "models").each do |model|
|
48
|
+
load model
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def establish_connection
|
53
|
+
ActiveRecord::Base.establish_connection @@config.connection_options
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'drb/acl'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Adhearsion
|
6
|
+
class Initializer
|
7
|
+
|
8
|
+
class DrbInitializer
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def start
|
13
|
+
config = Adhearsion::AHN_CONFIG.drb
|
14
|
+
DRb.install_acl ACL.new(config.acl) if config.acl
|
15
|
+
|
16
|
+
drb_door = Object.new
|
17
|
+
Components.component_manager.extend_object_with(drb_door, :rpc)
|
18
|
+
|
19
|
+
DRb.start_service "druby://#{config.host}:#{config.port}", drb_door
|
20
|
+
|
21
|
+
ahn_log "Starting DRb on #{config.host}:#{config.port}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
DRb.stop_service
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# THIS FREESWITCH LIBRARY HASN'T BEEN INTEGRATED INTO THE REFACTORED 0.8.0 YET.
|
2
|
+
# WHAT EXISTS HERE IS OLD, MUST BE CHANGED, AND DOES NOT EVEN GET LOADED AT THE MOMENT.
|
3
|
+
require "adhearsion/voip/freeswitch/oes_server"
|
4
|
+
require "adhearsion/voip/freeswitch/event_handler"
|
5
|
+
require "adhearsion/voip/freeswitch/inbound_connection_manager"
|
6
|
+
require "adhearsion/voip/dsl/dialplan/control_passing_exception"
|
7
|
+
|
8
|
+
oes_enabled = Adhearsion::Configuration.core.voip.freeswitch.oes && Adhearsion::Configuration.core.voip.freeswitch.oes.port
|
9
|
+
|
10
|
+
|
11
|
+
if oes_enabled
|
12
|
+
|
13
|
+
port = Adhearsion::Configuration.core.voip.freeswitch.oes.port
|
14
|
+
host = Adhearsion::Configuration.core.voip.freeswitch.oes.host
|
15
|
+
|
16
|
+
server = Adhearsion::VoIP::FreeSwitch::OesServer.new port, host
|
17
|
+
|
18
|
+
Events.register_callback(:after_initialized) { server.start }
|
19
|
+
Events.register_callback(:shutdown) { server.stop }
|
20
|
+
IMPORTANT_THREADS << server
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# TODO: Have all of the initializer modules required and then traverse the subclasses, asking them if they're enabled. If they are enabled, then they should do their initialization stuff. Is this really necessary to develop this entirely new system when the components system exists?
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
|
6
|
+
class LdapInitializer
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
require_dependencies
|
12
|
+
require_models
|
13
|
+
@@config = Adhearsion::AHN_CONFIG.ldap
|
14
|
+
# You may need to uncomment the following line for older versions of ActiveRecord
|
15
|
+
# ActiveRecord::Base.allow_concurrency = true
|
16
|
+
establish_connection
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
ActiveLdap::Base.remove_connection
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# TODO: It appears that ActiveLdap does not have a connection validation
|
26
|
+
# or reconnection routine.
|
27
|
+
#def create_call_hook_for_connection_cleanup
|
28
|
+
# Events.register_callback([:asterisk, :before_call]) do
|
29
|
+
# ActiveLdap::Base.verify_active_connections!
|
30
|
+
# end
|
31
|
+
#end
|
32
|
+
|
33
|
+
def require_dependencies
|
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
|
41
|
+
end
|
42
|
+
|
43
|
+
def require_models
|
44
|
+
AHN_CONFIG.files_from_setting("paths", "models").each do |model|
|
45
|
+
load model
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def establish_connection
|
50
|
+
ActiveLdap::Base.setup_connection @@config.connection_options
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'adhearsion/voip/asterisk'
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
class RailsInitializer
|
6
|
+
|
7
|
+
cattr_accessor :rails_root, :config, :environment
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
ahn_config = Adhearsion::AHN_CONFIG
|
12
|
+
self.config = ahn_config.rails
|
13
|
+
self.rails_root = config.rails_root
|
14
|
+
self.environment = config.environment
|
15
|
+
raise "You cannot enable the database and Rails at the same time!" if ahn_config.database_enabled?
|
16
|
+
raise "Error loading Rails environment in #{rails_root.inspect}. " +
|
17
|
+
"It's not a directory!" unless File.directory?(rails_root)
|
18
|
+
load_rails
|
19
|
+
if defined? ActiveRecord
|
20
|
+
# You may need to uncomment the following line for older versions of ActiveRecord
|
21
|
+
# ActiveRecord::Base.allow_concurrency = true
|
22
|
+
Events.register_callback([:asterisk, :before_call]) do
|
23
|
+
ActiveRecord::Base.verify_active_connections!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def load_rails
|
31
|
+
environment_file = File.expand_path(rails_root + "/config/environment.rb")
|
32
|
+
raise "There is no config/environment.rb file!" unless File.exists?(environment_file)
|
33
|
+
ENV['RAILS_ENV'] = environment.to_s
|
34
|
+
require environment_file
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'adhearsion/xmpp/connection.rb'
|
2
|
+
|
3
|
+
module Adhearsion
|
4
|
+
class Initializer
|
5
|
+
class XMPPInitializer
|
6
|
+
|
7
|
+
cattr_accessor :config, :jid, :password, :server, :port
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def start
|
11
|
+
require_dependencies
|
12
|
+
XMPP::Connection.extend Blather::DSL
|
13
|
+
ahn_config = Adhearsion::AHN_CONFIG
|
14
|
+
self.config = ahn_config.xmpp
|
15
|
+
self.jid = config.jid
|
16
|
+
self.password = config.password
|
17
|
+
self.server = config.server
|
18
|
+
self.port = config.port
|
19
|
+
|
20
|
+
XMPP::Connection.start(jid, password, server, port)
|
21
|
+
end
|
22
|
+
|
23
|
+
def stop
|
24
|
+
XMPP::Connection.stop
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def require_dependencies
|
30
|
+
begin
|
31
|
+
require 'blather/client/client'
|
32
|
+
require 'blather/client/dsl'
|
33
|
+
rescue LoadError
|
34
|
+
ahn_log.fatal "XMPP support requires the \"blather\" gem."
|
35
|
+
# Silence the abort so we don't get an ugly backtrace
|
36
|
+
abort ""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
module Adhearsion
|
2
|
+
|
3
|
+
mattr_accessor :status
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
##
|
8
|
+
# Shuts down the framework.
|
9
|
+
#
|
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
|
17
|
+
ahn_log "Shutting down gracefully at #{Time.now}."
|
18
|
+
self.status = :stopping
|
19
|
+
Events.trigger_immediately :shutdown
|
20
|
+
Events.stop!
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
class PathString < String
|
26
|
+
|
27
|
+
class << self
|
28
|
+
|
29
|
+
##
|
30
|
+
# Will return a PathString for the application root folder to which the specified arbitrarily nested subfolder belongs.
|
31
|
+
# It works by traversing parent directories looking for the .ahnrc file. If no .ahnrc is found, nil is returned.
|
32
|
+
#
|
33
|
+
# @param [String] folder The path to the directory which should be a
|
34
|
+
# @return [nil] if the subdirectory does not belong to a parent Adhearsion app directory
|
35
|
+
# @return [PathString] if a directory is found
|
36
|
+
#
|
37
|
+
def from_application_subdirectory(folder)
|
38
|
+
folder = File.expand_path folder
|
39
|
+
ahn_rc = nil
|
40
|
+
|
41
|
+
until ahn_rc || folder == "/"
|
42
|
+
possible_ahn_rc = File.join(folder, ".ahnrc")
|
43
|
+
if File.exists?(possible_ahn_rc)
|
44
|
+
ahn_rc = possible_ahn_rc
|
45
|
+
else
|
46
|
+
folder = File.expand_path(folder + "/..")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
ahn_rc ? new(folder) : nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_accessor :component_path, :dialplan_path, :log_path
|
54
|
+
|
55
|
+
def initialize(path)
|
56
|
+
super
|
57
|
+
defaults
|
58
|
+
end
|
59
|
+
|
60
|
+
def defaults
|
61
|
+
@component_path = build_path_for "components"
|
62
|
+
@dialplan_path = dup
|
63
|
+
@log_path = build_path_for "logs"
|
64
|
+
end
|
65
|
+
|
66
|
+
def base_path=(value)
|
67
|
+
replace(value)
|
68
|
+
defaults
|
69
|
+
end
|
70
|
+
|
71
|
+
def using_base_path(temporary_base_path, &block)
|
72
|
+
original_path = dup
|
73
|
+
self.base_path = temporary_base_path
|
74
|
+
block.call
|
75
|
+
ensure
|
76
|
+
self.base_path = original_path
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def build_path_for(path)
|
81
|
+
File.join(to_s, path)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Initializer
|
86
|
+
|
87
|
+
class << self
|
88
|
+
def get_rules_from(location)
|
89
|
+
location = File.join location, ".ahnrc" if File.directory? location
|
90
|
+
File.exists?(location) ? YAML.load_file(location) : nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def ahn_root=(path)
|
94
|
+
if Object.constants.include?("AHN_ROOT")
|
95
|
+
Object.const_get(:AHN_ROOT).base_path = File.expand_path(path)
|
96
|
+
else
|
97
|
+
Object.const_set(:AHN_ROOT, PathString.new(File.expand_path(path)))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def start(*args, &block)
|
102
|
+
new(*args, &block).start
|
103
|
+
end
|
104
|
+
|
105
|
+
def start_from_init_file(file, ahn_app_path)
|
106
|
+
return if defined?(@@started) && @@started
|
107
|
+
start ahn_app_path, :loaded_init_files => file
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
attr_reader :path, :daemon, :pid_file, :log_file, :ahn_app_log_directory
|
113
|
+
|
114
|
+
# Creation of pid_files
|
115
|
+
#
|
116
|
+
# - You may want to have Adhearsion create a process identification
|
117
|
+
# file when it boots so that a crash monitoring program such as
|
118
|
+
# Monit can reboot if necessary or so the init script can kill it
|
119
|
+
# for system shutdowns.
|
120
|
+
# - To have Adhearsion create a pid file in the default location (i.e.
|
121
|
+
# AHN_INSTALL_DIR/adhearsion.pid), supply :pid_file with 'true'. Otherwise
|
122
|
+
# one is not created UNLESS it is running in daemon mode, in which
|
123
|
+
# case one is created. You can force Adhearsion to not create one
|
124
|
+
# even in daemon mode by supplying "false".
|
125
|
+
def initialize(path=nil, options={})
|
126
|
+
@@started = true
|
127
|
+
@path = path
|
128
|
+
@daemon = options[:daemon] || ENV['DAEMON']
|
129
|
+
@pid_file = options[:pid_file].nil? ? ENV['PID_FILE'] : options[:pid_file]
|
130
|
+
@loaded_init_files = options[:loaded_init_files]
|
131
|
+
self.class.ahn_root = path
|
132
|
+
end
|
133
|
+
|
134
|
+
def start
|
135
|
+
Adhearsion.status = :starting
|
136
|
+
|
137
|
+
resolve_pid_file_path
|
138
|
+
resolve_log_file_path
|
139
|
+
daemonize! if should_daemonize?
|
140
|
+
switch_to_root_directory
|
141
|
+
catch_termination_signal
|
142
|
+
create_pid_file if pid_file
|
143
|
+
bootstrap_rc
|
144
|
+
initialize_log_file
|
145
|
+
load_all_init_files
|
146
|
+
init_datasources
|
147
|
+
init_components_subsystem
|
148
|
+
init_modules
|
149
|
+
init_events_subsystem
|
150
|
+
load_components
|
151
|
+
init_events_file
|
152
|
+
|
153
|
+
ahn_log "Adhearsion v#{Adhearsion::VERSION::STRING} initialized!"
|
154
|
+
Adhearsion.status = :running
|
155
|
+
|
156
|
+
trigger_after_initialized_hooks
|
157
|
+
join_important_threads
|
158
|
+
|
159
|
+
self
|
160
|
+
end
|
161
|
+
|
162
|
+
def default_pid_path
|
163
|
+
File.join AHN_ROOT, 'adhearsion.pid'
|
164
|
+
end
|
165
|
+
|
166
|
+
def resolve_pid_file_path
|
167
|
+
@pid_file = if pid_file.equal?(true) then default_pid_path
|
168
|
+
elsif pid_file then pid_file
|
169
|
+
elsif pid_file.equal?(false) then nil
|
170
|
+
# FIXME @pid_file = @daemon? Assignment or equality? I'm assuming equality.
|
171
|
+
else @pid_file = @daemon ? default_pid_path : nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def resolve_log_file_path
|
176
|
+
@ahn_app_log_directory = AHN_ROOT + '/log'
|
177
|
+
@log_file = File.expand_path(ahn_app_log_directory + "/adhearsion.log")
|
178
|
+
end
|
179
|
+
|
180
|
+
def switch_to_root_directory
|
181
|
+
Dir.chdir AHN_ROOT
|
182
|
+
end
|
183
|
+
|
184
|
+
def catch_termination_signal
|
185
|
+
%w'INT TERM'.each do |process_signal|
|
186
|
+
trap process_signal do
|
187
|
+
Adhearsion.shutdown!
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# This step in the initialization process loads the .ahnrc in the given app folder. With the information in .ahnrc, we
|
194
|
+
# can continue the initialization knowing where certain files are specifically.
|
195
|
+
#
|
196
|
+
def bootstrap_rc
|
197
|
+
rules = self.class.get_rules_from AHN_ROOT
|
198
|
+
|
199
|
+
AHN_CONFIG.ahnrc = rules
|
200
|
+
|
201
|
+
# DEPRECATION: Check if the old paths format is being used. If so, abort and notify.
|
202
|
+
if rules.has_key?("paths") && rules["paths"].kind_of?(Hash)
|
203
|
+
paths = rules["paths"].each_pair do |key,value|
|
204
|
+
if value.kind_of?(Hash)
|
205
|
+
if value.has_key?("directory") || value.has_key?("pattern")
|
206
|
+
puts
|
207
|
+
puts *caller
|
208
|
+
puts
|
209
|
+
|
210
|
+
abort <<-WARNING
|
211
|
+
Deprecation Warning
|
212
|
+
-------------------
|
213
|
+
The (hidden) .ahnrc file in this app is of an older format and needs to be fixed.
|
214
|
+
|
215
|
+
There is a rake task to automatically fix it or you can do it manually. Note: it's
|
216
|
+
best if you do it manually so you can retain the YAML comments in your .ahnrc file.
|
217
|
+
|
218
|
+
The rake task is called "deprecations:fix_ahnrc_path_format".
|
219
|
+
|
220
|
+
To do it manually, find all entries in the "paths" section of your ".ahnrc" file
|
221
|
+
which look like the following:
|
222
|
+
|
223
|
+
paths:
|
224
|
+
key_name_could_be_anything:
|
225
|
+
directory: some_folder
|
226
|
+
pattern: *.rb
|
227
|
+
|
228
|
+
Note: the "models" section had this syntax before:
|
229
|
+
|
230
|
+
models:
|
231
|
+
directory: models
|
232
|
+
pattern: "*.rb"
|
233
|
+
|
234
|
+
The NEW syntax is as follows (using models as an example):
|
235
|
+
|
236
|
+
models: models/*.rb
|
237
|
+
|
238
|
+
This new format is much cleaner.
|
239
|
+
|
240
|
+
Adhearsion will abort until you fix this. Sorry for the incovenience.
|
241
|
+
WARNING
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
gems = rules['gems']
|
248
|
+
if gems.kind_of?(Hash) && gems.any? && respond_to?(:gem)
|
249
|
+
gems.each_pair do |gem_name,properties_hash|
|
250
|
+
if properties_hash && properties_hash["version"]
|
251
|
+
gem gem_name, properties_hash["version"]
|
252
|
+
else
|
253
|
+
gem gem_name
|
254
|
+
end
|
255
|
+
if properties_hash
|
256
|
+
case properties_hash["require"]
|
257
|
+
when Array
|
258
|
+
properties_hash["require"].each { |lib| require lib }
|
259
|
+
when String
|
260
|
+
require properties_hash["require"]
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def load_all_init_files
|
268
|
+
init_files_from_rc = AHN_CONFIG.files_from_setting("paths", "init").map { |file| File.expand_path(file) }
|
269
|
+
already_loaded_init_files = Array(@loaded_init_files).map { |file| File.expand_path(file) }
|
270
|
+
(init_files_from_rc - already_loaded_init_files).each { |init| load init }
|
271
|
+
end
|
272
|
+
|
273
|
+
def init_datasources
|
274
|
+
require 'adhearsion/initializer/database.rb'
|
275
|
+
require 'adhearsion/initializer/ldap.rb'
|
276
|
+
|
277
|
+
DatabaseInitializer.start if AHN_CONFIG.database_enabled?
|
278
|
+
LdapInitializer.start if AHN_CONFIG.ldap_enabled?
|
279
|
+
end
|
280
|
+
|
281
|
+
def init_modules
|
282
|
+
|
283
|
+
require 'adhearsion/initializer/asterisk.rb'
|
284
|
+
require 'adhearsion/initializer/drb.rb'
|
285
|
+
require 'adhearsion/initializer/rails.rb'
|
286
|
+
require 'adhearsion/initializer/xmpp.rb'
|
287
|
+
# require 'adhearsion/initializer/freeswitch.rb'
|
288
|
+
|
289
|
+
AsteriskInitializer.start if AHN_CONFIG.asterisk_enabled?
|
290
|
+
DrbInitializer.start if AHN_CONFIG.drb_enabled?
|
291
|
+
RailsInitializer.start if AHN_CONFIG.rails_enabled?
|
292
|
+
XMPPInitializer.start if AHN_CONFIG.xmpp_enabled?
|
293
|
+
# FreeswitchInitializer.start if AHN_CONFIG.freeswitch_enabled?
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
def init_events_subsystem
|
298
|
+
application_events_files = AHN_CONFIG.files_from_setting("paths", "events")
|
299
|
+
if application_events_files.any?
|
300
|
+
Events.register_callback(:shutdown) do
|
301
|
+
ahn_log.events "Performing a graceful stop of events subsystem"
|
302
|
+
Events.framework_theatre.graceful_stop!
|
303
|
+
end
|
304
|
+
Events.framework_theatre.start!
|
305
|
+
else
|
306
|
+
ahn_log.events.warn 'No entries in the "events" section of .ahnrc. Skipping its initialization.'
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def init_events_file
|
311
|
+
application_events_files = AHN_CONFIG.files_from_setting("paths", "events")
|
312
|
+
application_events_files.each do |file|
|
313
|
+
Events.framework_theatre.load_events_file file
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def should_daemonize?
|
318
|
+
@daemon
|
319
|
+
end
|
320
|
+
|
321
|
+
def daemonize!
|
322
|
+
ahn_log "Daemonizing now! Creating #{pid_file}."
|
323
|
+
extend Adhearsion::CustomDaemonizer
|
324
|
+
daemonize log_file
|
325
|
+
end
|
326
|
+
|
327
|
+
def initialize_log_file
|
328
|
+
Dir.mkdir(ahn_app_log_directory) unless File.directory? ahn_app_log_directory
|
329
|
+
file_logger = Log4r::FileOutputter.new("Main Adhearsion log file", :filename => log_file, :trunc => false)
|
330
|
+
|
331
|
+
if should_daemonize?
|
332
|
+
Logging::AdhearsionLogger.outputters = file_logger
|
333
|
+
else
|
334
|
+
Logging::AdhearsionLogger.outputters << file_logger
|
335
|
+
end
|
336
|
+
Logging::DefaultAdhearsionLogger.redefine_outputters
|
337
|
+
end
|
338
|
+
|
339
|
+
def create_pid_file
|
340
|
+
if pid_file
|
341
|
+
File.open pid_file, 'w' do |file|
|
342
|
+
file.puts Process.pid
|
343
|
+
end
|
344
|
+
|
345
|
+
Events.register_callback :shutdown do
|
346
|
+
File.delete(pid_file) if File.exists?(pid_file)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def init_components_subsystem
|
352
|
+
@components_directory = File.expand_path "components"
|
353
|
+
if File.directory? @components_directory
|
354
|
+
Components.component_manager = Components::ComponentManager.new @components_directory
|
355
|
+
Kernel.send(:const_set, :COMPONENTS, Components.component_manager.lazy_config_loader)
|
356
|
+
Components.component_manager.globalize_global_scope!
|
357
|
+
Components.component_manager.extend_object_with(Theatre::CallbackDefinitionLoader, :events)
|
358
|
+
else
|
359
|
+
ahn_log.warn "No components directory found. Not initializing any components."
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def load_components
|
364
|
+
if Components.component_manager
|
365
|
+
Components.component_manager.load_components
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def trigger_after_initialized_hooks
|
370
|
+
Events.trigger_immediately :after_initialized
|
371
|
+
end
|
372
|
+
|
373
|
+
##
|
374
|
+
# This method will block Thread.main() until calling join() has returned for all Threads in IMPORTANT_THREADS.
|
375
|
+
# Note: IMPORTANT_THREADS won't always contain Thread instances. It simply requires the objects respond to join().
|
376
|
+
#
|
377
|
+
def join_important_threads
|
378
|
+
# Note: we're using this ugly accumulator to ensure that all threads have ended since IMPORTANT_THREADS will almost
|
379
|
+
# certainly change sizes after this method is called.
|
380
|
+
index = 0
|
381
|
+
until index == IMPORTANT_THREADS.size
|
382
|
+
begin
|
383
|
+
IMPORTANT_THREADS[index].join
|
384
|
+
rescue => e
|
385
|
+
ahn_log.error "Error after join()ing Thread #{thread.inspect}. #{e.message}"
|
386
|
+
ensure
|
387
|
+
index = index + 1
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
class InitializationFailedError < StandardError; end
|
393
|
+
end
|
394
|
+
end
|