X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=lib%2Frbot%2Fircbot.rb;h=87d4f3eb40edfcb702941b809380afb2919395b2;hb=4a86158144a13bc901222442ccd2db9c2bbd6bb0;hp=649c02eda8cb23330cb71bc88e750cc6dda508d3;hpb=cfb41ae15b48e167c76f97fb20ca382ba3dd5032;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/lib/rbot/ircbot.rb b/lib/rbot/ircbot.rb index 649c02ed..87d4f3eb 100644 --- a/lib/rbot/ircbot.rb +++ b/lib/rbot/ircbot.rb @@ -10,9 +10,26 @@ $daemonize = false unless $daemonize $dateformat = "%Y/%m/%d %H:%M:%S" $logger = Logger.new($stderr) $logger.datetime_format = $dateformat -$logger.level = $cl_loglevel if $cl_loglevel +$logger.level = $cl_loglevel if defined? $cl_loglevel $logger.level = 0 if $debug +require 'pp' + +unless Kernel.instance_methods.include?("pretty_inspect") + def pretty_inspect + PP.pp(self, '') + end + public :pretty_inspect +end + +class Exception + def pretty_print(q) + q.group(1, "#<%s: %s" % [self.class, self.message], ">") { + q.seplist(self.backtrace, lambda { "\n" }) { |v| v } if self.backtrace + } + end +end + def rawlog(level, message=nil, who_pos=1) call_stack = caller if call_stack.length > who_pos @@ -23,7 +40,14 @@ def rawlog(level, message=nil, who_pos=1) # Output each line. To distinguish between separate messages and multi-line # messages originating at the same time, we blank #{who} after the first message # is output. - message.to_s.each_line { |l| + # Also, we output strings as-is but for other objects we use pretty_inspect + case message + when String + str = message + else + str = message.pretty_inspect + end + str.each_line { |l| $logger.add(level, l.chomp, who) who.gsub!(/./," ") } @@ -68,6 +92,7 @@ $interrupted = 0 # these first require 'rbot/rbotconfig' +require 'rbot/load-gettext' require 'rbot/config' # require 'rbot/utils' @@ -193,7 +218,7 @@ class Bot :default => [], :wizard => true, :desc => "What channels the bot should always join at startup. List multiple channels using commas to separate. If a channel requires a password, use a space after the channel name. e.g: '#chan1, #chan2, #secretchan secritpass, #chan3'") BotConfig.register BotConfigArrayValue.new('irc.ignore_users', - :default => [], + :default => [], :desc => "Which users to ignore input from. This is mainly to avoid bot-wars triggered by creative people") BotConfig.register BotConfigIntegerValue.new('core.save_every', @@ -289,6 +314,7 @@ class Bot :desc => "When truncating overlong messages (see send.overlong) or when sending too many lines per message (see send.max_lines) replace the end of the last line with this text") @argv = params[:argv] + @run_dir = params[:run_dir] || Dir.pwd unless FileTest.directory? Config::coredir error "core directory '#{Config::coredir}' not found, did you setup.rb?" @@ -343,9 +369,8 @@ class Bot begin @config = BotConfig.configmanager @config.bot_associate(self) - rescue => e - fatal e.inspect - fatal e.backtrace.join("\n") + rescue Exception => e + fatal e log_session_end exit 2 end @@ -360,7 +385,7 @@ class Bot end # See http://blog.humlab.umu.se/samuel/archives/000107.html - # for the backgrounding code + # for the backgrounding code if $daemonize begin exit if fork @@ -368,8 +393,10 @@ class Bot exit if fork rescue NotImplementedError warning "Could not background, fork not supported" - rescue => e - warning "Could not background. #{e.inspect}" + rescue SystemExit + exit 0 + rescue Exception => e + warning "Could not background. #{e.pretty_inspect}" end Dir.chdir botclass # File.umask 0000 # Ensure sensible umask. Adjust as needed. @@ -398,11 +425,15 @@ class Bot $logger = Logger.new(@logfile, @config['log.keep'], @config['log.max_size']*1024*1024) $logger.datetime_format= $dateformat $logger.level = @config['log.level'] - $logger.level = $cl_loglevel if $cl_loglevel + $logger.level = $cl_loglevel if defined? $cl_loglevel $logger.level = 0 if $debug log_session_start + File.open($opts['pidfile'] || "#{@botclass}/rbot.pid", 'w') do |pf| + pf << "#{$$}\n" + end + @registry = BotRegistry.new self @timer = Timer::Timer.new(1.0) # only need per-second granularity @@ -423,9 +454,8 @@ class Bot @auth = Auth::authmanager @auth.bot_associate(self) # @auth.load("#{botclass}/botusers.yaml") - rescue => e - fatal e.inspect - fatal e.backtrace.join("\n") + rescue Exception => e + fatal e log_session_end exit 2 end @@ -526,7 +556,7 @@ class Bot } } @client[:nicktaken] = proc { |data| - new = "#{data[:nick]}_" + new = "#{data[:nick]}_" nickchg new # If we're setting our nick at connection because our choice was taken, # we have to fix our nick manually, because there will be no NICK message @@ -538,7 +568,7 @@ class Bot @plugins.delegate "nicktaken", data[:nick] } @client[:badnick] = proc {|data| - arning "bad nick (#{data[:nick]})" + warning "bad nick (#{data[:nick]})" } @client[:ping] = proc {|data| sendq "PONG #{data[:pingid]}" @@ -581,6 +611,7 @@ class Bot @plugins.delegate("listen", m) @plugins.delegate("join", m) + sendq "WHO #{data[:channel]}", data[:channel], 2 } @client[:part] = proc {|data| m = PartMessage.new(self, server, data[:source], data[:channel], data[:message]) @@ -711,9 +742,9 @@ class Bot trap("SIGTERM") { got_sig("SIGTERM") } trap("SIGHUP") { got_sig("SIGHUP") } rescue ArgumentError => e - debug "failed to trap signals (#{e.inspect}): running on Windows?" - rescue => e - debug "failed to trap signals: #{e.inspect}" + debug "failed to trap signals (#{e.pretty_inspect}): running on Windows?" + rescue Exception => e + debug "failed to trap signals: #{e.pretty_inspect}" end begin quit if $interrupted > 0 @@ -724,7 +755,7 @@ class Bot quit if $interrupted > 0 realname = @config['irc.name'].clone || 'Ruby bot' - realname << ' ' + COPYRIGHT_NOTICE if @config['irc.name_copyright'] + realname << ' ' + COPYRIGHT_NOTICE if @config['irc.name_copyright'] @socket.emergency_puts "PASS " + @config['server.password'] if @config['server.password'] @socket.emergency_puts "NICK #{@config['irc.nick']}\nUSER #{@config['irc.user']} 4 #{@socket.server_uri.host} :#{realname}" @@ -765,24 +796,20 @@ class Bot log_session_end exit 0 rescue Errno::ETIMEDOUT, Errno::ECONNABORTED, TimeoutError, SocketError => e - error "network exception: #{e.class}: #{e}" - debug e.backtrace.join("\n") + error "network exception: #{e.pretty_inspect}" quit_msg = e.to_s rescue BDB::Fatal => e - fatal "fatal bdb error: #{e.class}: #{e}" - fatal e.backtrace.join("\n") + fatal "fatal bdb error: #{e.pretty_inspect}" DBTree.stats # Why restart? DB problems are serious stuff ... # restart("Oops, we seem to have registry problems ...") log_session_end exit 2 rescue Exception => e - error "non-net exception: #{e.class}: #{e}" - error e.backtrace.join("\n") + error "non-net exception: #{e.pretty_inspect}" quit_msg = e.to_s rescue => e - fatal "unexpected exception: #{e.class}: #{e}" - fatal e.backtrace.join("\n") + fatal "unexpected exception: #{e.pretty_inspect}" log_session_end exit 2 end @@ -902,7 +929,6 @@ class Bot else lines = all_lines end - debug lines.inspect lines.each { |line| sendq "#{fixed}#{line}", chan, ring @@ -986,8 +1012,8 @@ class Bot sendq "TOPIC #{where} :#{topic}", where, 2 end - def disconnect(message = nil) - message = @lang.get("quit") if (message.nil? || message.empty?) + def disconnect(message=nil) + message = @lang.get("quit") if (!message || message.empty?) if @socket.connected? debug "Clearing socket" @socket.clearq @@ -1007,9 +1033,9 @@ class Bot end # disconnect from the server and cleanup all plugins and modules - def shutdown(message = nil) + def shutdown(message=nil) @quit_mutex.synchronize do - debug "Shutting down ..." + debug "Shutting down: #{message}" ## No we don't restore them ... let everything run through # begin # trap("SIGINT", "DEFAULT") @@ -1018,16 +1044,19 @@ class Bot # rescue => e # debug "failed to restore signals: #{e.inspect}\nProbably running on windows?" # end - disconnect - debug "Saving" + debug "\tdisconnecting..." + disconnect(message) + debug "\tsaving ..." save - debug "Cleaning up" + debug "\tcleaning up ..." @save_mutex.synchronize do @plugins.cleanup end + debug "\tstopping timers ..." + @timer.stop # debug "Closing registries" # @registry.close - debug "Cleaning up the db environment" + debug "\t\tcleaning up the db environment ..." DBTree.cleanup_env log "rbot quit (#{message})" end @@ -1044,13 +1073,22 @@ class Bot end # totally shutdown and respawn the bot - def restart(message = false) - msg = message ? message : "restarting, back in #{@config['server.reconnect_wait']}..." - shutdown(msg) + def restart(message=nil) + message = "restarting, back in #{@config['server.reconnect_wait']}..." if (!message || message.empty?) + shutdown(message) sleep @config['server.reconnect_wait'] - # now we re-exec - # Note, this fails on Windows - exec($0, *@argv) + begin + # now we re-exec + # Note, this fails on Windows + debug "going to exec #{$0} #{@argv.inspect} from #{@run_dir}" + Dir.chdir(@run_dir) + exec($0, *@argv) + rescue Errno::ENOENT + exec("ruby", *(@argv.unshift $0)) + rescue Exception => e + $interrupted += 1 + raise e + end end # call the save method for all of the botmodules @@ -1107,12 +1145,12 @@ class Bot topic = nil if topic == "" case topic when nil - helpstr = "help topics: " + helpstr = _("help topics: ") helpstr += @plugins.helptopics - helpstr += " (help for more info)" + helpstr += _(" (help for more info)") else unless(helpstr = @plugins.help(topic)) - helpstr = "no help for topic #{topic}" + helpstr = _("no help for topic %{topic}") % { :topic => topic } end end return helpstr @@ -1123,7 +1161,11 @@ class Bot secs_up = Time.new - @startup_time uptime = Utils.secs_to_string secs_up # return "Uptime #{uptime}, #{@plugins.length} plugins active, #{@registry.length} items stored in registry, #{@socket.lines_sent} lines sent, #{@socket.lines_received} received." - return "Uptime #{uptime}, #{@plugins.length} plugins active, #{@socket.lines_sent} lines sent, #{@socket.lines_received} received." + return (_("Uptime %{up}, %{plug} plugins active, %{sent} lines sent, %{recv} received.") % + { + :up => uptime, :plug => @plugins.length, + :sent => @socket.lines_sent, :recv => @socket.lines_received + }) end # We want to respond to a hung server in a timely manner. If nothing was received