# -*- encoding: utf-8 -*- require 'fileutils' require 'rbconfig' require 'evented_bluepill/options' module EventedBluepill class Controller attr_accessor :base_dir, :log_file def initialize() self.log_file = EventedBluepill::Options[:log_file] self.base_dir = EventedBluepill::Options[:base_dir] setup_dir_structure cleanup_bluepill_directory end def handle_command(application, command, *args) case command.to_sym when :load file = args.first if File.exists?(file) # Restart the ruby interpreter for the config file so that anything loaded here # does not stay in memory for the daemon ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) load_path = File.expand_path("#{File.dirname(__FILE__)}/../") file_path = File.expand_path(file) exec(ruby, "-I#{load_path}", '-revented_bluepill', file_path) else $stderr.puts "Can't find file: #{file}" end when :status puts self.send_to_daemon(application, :status, *args) when *Application::PROCESS_COMMANDS # these need to be sent to the daemon and the results printed out affected = self.send_to_daemon(application, command, *args) if affected.empty? puts "No processes effected" else puts "Sent #{command} to:" affected.each do |process| puts " #{process}" end end when :quit pid = pid_for(application) if System.pid_alive?(pid) ::Process.kill("TERM", pid) puts "Killing evented_bluepilld[#{pid}]" else puts "evented_bluepilld[#{pid}] not running" end when :log log_file_location = self.send_to_daemon(application, :log_file) log_file_location = self.log_file if log_file_location.to_s.strip.empty? requested_pattern = args.first grep_pattern = self.grep_pattern(application, requested_pattern) tail = "tail -n 100 -f #{log_file_location} | grep -E '#{grep_pattern}'" puts "Tailing log for #{requested_pattern}..." Kernel.exec(tail) else $stderr.puts "Unknown command `%s` (or application `%s` has not been loaded yet)" % [command, command] exit(1) end end def send_to_daemon(application, command, *args) begin verify_version!(application) command = ([command, *args]).join(":") response = Socket.client_command(base_dir, application, command) if response.is_a?(Exception) $stderr.puts "Received error from server:" $stderr.puts response.inspect $stderr.puts response.backtrace.join("\n") exit(8) else response end rescue Errno::ECONNREFUSED abort("Connection Refused: Server is not running") end end def grep_pattern(application, query = nil) pattern = [application, query].compact.join(':') ['\[.*', Regexp.escape(pattern), '.*'].compact.join end private def cleanup_bluepill_directory EventedBluepill::Options.running_applications.each do |app| pid = pid_for(app) if !pid || !System.pid_alive?(pid) pid_file = File.join(EventedBluepill::Options.pids_dir, "#{app}.pid") sock_file = File.join(EventedBluepill::Options.sockets_dir, "#{app}.sock") File.unlink(pid_file) if File.exists?(pid_file) File.unlink(sock_file) if File.exists?(sock_file) end end end def pid_for(app) pid_file = File.join(self.pids_dir, "#{app}.pid") File.exists?(pid_file) && File.read(pid_file).to_i end def setup_dir_structure [EventedBluepill::Options.sockets_dir, EventedBluepill::Options.pids_dir].each do |dir| FileUtils.mkdir_p(dir) unless File.exists?(dir) end end def verify_version!(application) begin version = Socket.client_command(base_dir, application, "version") if version != EventedBluepill::VERSION::STRING abort("The running version of your daemon seems to be out of date.\nDaemon Version: #{version}, CLI Version: #{EventedBluepill::VERSION::STRING}") end rescue ArgumentError abort("The running version of your daemon seems to be out of date.") end end end end