# encoding: utf-8 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_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_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