]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - lib/rbot/ircbot.rb
* unicode.rb: @old_kcode --> @@old_kcode [we aren't always called as an instance]
[user/henk/code/ruby/rbot.git] / lib / rbot / ircbot.rb
index cd073b327448f6a054889bea2869c051b8337f36..baf520056dc3dbfc92c69008c6a7400b02d23ba0 100644 (file)
@@ -18,6 +18,9 @@ $logger.datetime_format = $dateformat
 $logger.level = $cl_loglevel if defined? $cl_loglevel
 $logger.level = 0 if $debug
 
+$log_queue = Queue.new
+$log_thread = nil
+
 require 'pp'
 
 unless Kernel.instance_methods.include?("pretty_inspect")
@@ -39,37 +42,55 @@ class Exception
 end
 
 def rawlog(level, message=nil, who_pos=1)
-  begin
-    call_stack = caller
-    if call_stack.length > who_pos
-      who = call_stack[who_pos].sub(%r{(?:.+)/([^/]+):(\d+)(:in .*)?}) { "#{$1}:#{$2}#{$3}" }
-    else
-      who = "(unknown)"
-    end
-    # 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.
-    # 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
+  call_stack = caller
+  if call_stack.length > who_pos
+    who = call_stack[who_pos].sub(%r{(?:.+)/([^/]+):(\d+)(:in .*)?}) { "#{$1}:#{$2}#{$3}" }
+  else
+    who = "(unknown)"
+  end
+  # 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.
+  # 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
+  qmsg = Array.new
+  str.each_line { |l|
+    qmsg.push [level, l.chomp, who]
+    who = ' ' * who.size
+  }
+  $log_queue.push qmsg
+end
+
+def restart_logger
+  if $log_thread && $log_thread.alive?
+    $log_queue << nil
+    $log_thread.join
+    $log_thread = nil
+  end
+
+  $log_thread = Thread.new do
+    ls = nil
+    while ls = $log_queue.pop
+      ls.each { |l| $logger.add(*l) }
     end
-    str.each_line { |l|
-      $logger.add(level, l.chomp, who)
-      who.gsub!(/./," ")
-    }
-  rescue SecurityError
   end
 end
 
+restart_logger
+
 def log_session_start
   $logger << "\n\n=== #{botclass} session started on #{Time.now.strftime($dateformat)} ===\n\n"
+  restart_logger
 end
 
 def log_session_end
   $logger << "\n\n=== #{botclass} session ended on #{Time.now.strftime($dateformat)} ===\n\n"
+  $log_queue << nil
 end
 
 def debug(message=nil, who_pos=1)
@@ -442,17 +463,20 @@ class Bot
       Dir.chdir botclass
       # File.umask 0000                # Ensure sensible umask. Adjust as needed.
       log "Redirecting standard input/output/error"
-      begin
-        STDIN.reopen "/dev/null"
-      rescue Errno::ENOENT
-        # On Windows, there's not such thing as /dev/null
-        STDIN.reopen "NUL"
+      [$stdin, $stdout, $stderr].each do |fd|
+        begin
+          fd.reopen "/dev/null"
+        rescue Errno::ENOENT
+          # On Windows, there's not such thing as /dev/null
+          fd.reopen "NUL"
+        end
       end
-      def STDOUT.write(str=nil)
+
+      def $stdout.write(str=nil)
         log str, 2
         return str.to_s.size
       end
-      def STDERR.write(str=nil)
+      def $stdout.write(str=nil)
         if str.to_s.match(/:\d+: warning:/)
           warning str, 2
         else
@@ -680,6 +704,8 @@ class Bot
       :split_at => Regexp.new(@config['send.split_at']),
       :purge_split => @config['send.purge_split'],
       :truncate_text => @config['send.truncate_text'].dup
+
+    trap_sigs
   end
 
   def setup_plugins_path
@@ -737,10 +763,10 @@ class Bot
   end
 
   # things to do when we receive a signal
-  def got_sig(sig)
-    debug "received #{sig}, queueing quit"
+  def got_sig(sig, func=:quit)
+    debug "received #{sig}, queueing #{func}"
     $interrupted += 1
-    quit unless @quit_mutex.locked?
+    self.send(func) unless @quit_mutex.locked?
     debug "interrupted #{$interrupted} times"
     if $interrupted >= 3
       debug "drastic!"
@@ -749,17 +775,21 @@ class Bot
     end
   end
 
-  # connect the bot to IRC
-  def connect
+  # trap signals
+  def trap_sigs
     begin
       trap("SIGINT") { got_sig("SIGINT") }
       trap("SIGTERM") { got_sig("SIGTERM") }
-      trap("SIGHUP") { got_sig("SIGHUP") }
+      trap("SIGHUP") { got_sig("SIGHUP", :restart) }
     rescue ArgumentError => e
       debug "failed to trap signals (#{e.pretty_inspect}): running on Windows?"
     rescue Exception => e
       debug "failed to trap signals: #{e.pretty_inspect}"
     end
+  end
+
+  # connect the bot to IRC
+  def connect
     begin
       quit if $interrupted > 0
       @socket.connect
@@ -1065,9 +1095,11 @@ class Bot
       # now we re-exec
       # Note, this fails on Windows
       debug "going to exec #{$0} #{@argv.inspect} from #{@run_dir}"
+      log_session_end
       Dir.chdir(@run_dir)
       exec($0, *@argv)
     rescue Errno::ENOENT
+      log_session_end
       exec("ruby", *(@argv.unshift $0))
     rescue Exception => e
       $interrupted += 1