lib/adhearsion/initializer.rb
# encoding: utf-8
require 'adhearsion/application'
require 'adhearsion/linux_proc_name'
require 'adhearsion/rayo/initializer'
require 'adhearsion/http_server'
require 'rbconfig'
module Adhearsion
class Initializer
class << self
def start(*args, &block)
new(*args, &block).start
end
end
attr_reader :path
def initialize(options = {})
@@started = true
@path = path
@console = options[:console]
@loaded_init_files = options[:loaded_init_files]
Adhearsion.root = '.'
end
def start
catch :boot_aborted do
configure_plugins
load_lib_folder
load_app_file
load_config_file
load_events_file
load_routes_file
Adhearsion.statistics
start_logging
debugging_log
launch_console if need_console?
catch_termination_signal
set_ahn_proc_name
initialize_exception_logger
setup_i18n_load_path
Rayo::Initializer.init
HTTPServer.start
init_plugins
Rayo::Initializer.run
run_plugins
trigger_after_initialized_hooks
Adhearsion::Process.booted if Adhearsion.status == :booting
logger.info "Adhearsion v#{Adhearsion::VERSION} initialized in \"#{Adhearsion.environment}\"!" if Adhearsion.status == :running
end
# This method will block until all important threads have finished.
# When it does, the process will exit.
join_important_threads
self
end
def debugging_items
[
"OS: #{RbConfig::CONFIG['host_os']} - RUBY: #{RUBY_ENGINE} #{RUBY_VERSION}",
"Environment: #{ENV.inspect}",
Adhearsion.config.description(:all),
"Gem versions: #{Gem.loaded_specs.inject([]) { |c,g| c << "#{g[0]} #{g[1].version}" }}"
]
end
def debugging_log
debugging_items.each do |item|
logger.trace item
end
end
def setup_i18n_load_path
Adhearsion.config.core.i18n.locale_path.each do |dir|
logger.debug "Adding #{dir} to the I18n load path"
I18n.load_path += Dir["#{dir}/**/*.yml"]
end
end
def catch_termination_signal
self_read, self_write = IO.pipe
%w(INT TERM HUP ALRM ABRT).each do |sig|
trap sig do
self_write.puts sig
end
end
Thread.new do
begin
while readable_io = IO.select([self_read])
signal = readable_io.first[0].gets.strip
handle_signal signal
end
rescue => e
logger.error "Crashed reading signals"
logger.error e
exit 1
end
end
end
def handle_signal(signal)
case signal
when 'INT', 'TERM'
logger.info "Received SIG#{signal}. Shutting down."
Adhearsion::Process.shutdown
when 'ALRM'
logger.info "Received SIGALRM. Toggling trace logging."
Adhearsion::Logging.toggle_trace!
when 'ABRT'
logger.info "Received ABRT signal. Forcing stop."
Adhearsion::Process.force_stop
end
end
##
# Loads files in application lib folder
# @return [Boolean] if files have been loaded (lib folder is configured to not nil and actually exists)
def load_lib_folder
return false if Adhearsion.config.core.lib.nil?
lib_folder = [Adhearsion.config.core.root, Adhearsion.config.core.lib].join '/'
return false unless File.directory? lib_folder
$LOAD_PATH.unshift lib_folder
Dir.chdir lib_folder do
rbfiles = File.join "**", "*.rb"
Dir.glob(rbfiles).each do |file|
require "#{lib_folder}/#{file}"
end
end
true
end
def load_app_file
path = "#{Adhearsion.config.root}/config/app.rb"
load path if File.exists?(path)
end
def load_config_file
load "#{Adhearsion.config.root}/config/adhearsion.rb"
end
def load_events_file
Adhearsion::Events.init
path = "#{Adhearsion.config.root}/config/events.rb"
load path if File.exists?(path)
end
def load_routes_file
path = "#{Adhearsion.config.root}/config/routes.rb"
load path if File.exists?(path)
end
def configure_plugins
Plugin.configure_plugins
end
def init_plugins
Plugin.init_plugins
end
def run_plugins
Plugin.run_plugins
end
def need_console?
@console == true
end
def launch_console
Thread.new do
catching_standard_errors do
Adhearsion::Console.run
end
end
end
def start_logging
Adhearsion::Logging.start Adhearsion.config.core.logging.level, Adhearsion.config.core.logging.formatter
end
def initialize_exception_logger
Events.register_handler :exception do |e, l|
(l || logger).error e
end
end
def set_ahn_proc_name
Adhearsion::LinuxProcName.set_proc_name Adhearsion.config.core.process_name
end
def trigger_after_initialized_hooks
Events.trigger_immediately :after_initialized
end
##
# This method will block Thread.main() until calling join() has returned for all Threads in Adhearsion::Process.important_threads.
# Note: important_threads won't always contain Thread instances. It simply requires the objects respond to join().
#
def join_important_threads
# Note: we're using this ugly accumulator to ensure that all threads have ended since IMPORTANT_THREADS will almost
# certainly change sizes after this method is called.
index = 0
until index == Adhearsion::Process.important_threads.size
begin
Adhearsion::Process.important_threads[index].join
rescue => e
logger.error "Error after joining Thread #{Thread.inspect}. #{e.message}"
ensure
index = index + 1
end
end
end
InitializationFailedError = Class.new Adhearsion::Error
end
end