OSDN Git Service

- shogi_server/players.rb: When a player was finishing with its
[shogi-server/shogi-server.git] / shogi_server / player.rb
index e8aaf9f..e9280de 100644 (file)
@@ -97,6 +97,7 @@ end
 
 
 class Player < BasicPlayer
+  WRITE_THREAD_WATCH_INTERVAL = 20 # sec
   def initialize(str, socket, eol=nil)
     super()
     @socket = socket
@@ -110,7 +111,7 @@ class Player < BasicPlayer
     @sente = nil
     @socket_buffer = []
     @main_thread = Thread::current
-    @write_queue = Queue.new
+    @write_queue = ShogiServer::TimeoutQueue.new(WRITE_THREAD_WATCH_INTERVAL)
     @player_logger = nil
     start_write_thread
   end
@@ -170,10 +171,12 @@ class Player < BasicPlayer
       @status = "finished"
       log_message(sprintf("user %s finish", @name))    
       begin
-#        @socket.close if (! @socket.closed?)
-        write_safe(nil)
-        @write_thread.join
-        @player_logger.close
+        log_debug("Terminating %s's write thread..." % [@name])
+        if @write_thread && @write_thread.alive?
+          write_safe(nil)
+        end
+        @player_logger.close if @player_logger
+        log_debug("done.")
       rescue
         log_message(sprintf("user %s finish failed", @name))    
       end
@@ -184,39 +187,40 @@ class Player < BasicPlayer
     @write_thread = Thread.start do
       Thread.pass
       while !@socket.closed?
-        str = ""
         begin
-          begin
-            timeout(5) do
-              str = @write_queue.deq
-            end
-            if str == nil
-              break
-            end
-          rescue TimeoutError
+          str = @write_queue.deq
+          if (str == nil)
+            log_debug("%s's write thread terminated" % [@name])
+            break
+          end
+          if (str == :timeout)
+            log_debug("%s's write queue timed out. Try again..." % [@name])
             next
           end
+
           if r = select(nil, [@socket], nil, 20)
             r[1].first.write(str)
             log(:info, :out, str)
           else
-            log_error("Sending a message to #{@name} timed up.")
+            log_error("Gave a try to send a message to #{@name}, but it timed out.")
+            break
           end
         rescue Exception => ex
           log_error("Failed to send a message to #{@name}. #{ex.class}: #{ex.message}\t#{ex.backtrace[0]}")
+          break
         end
       end # while loop
-      log_message("terminated %s's write thread" % [@name])
+      log_error("%s's socket closed." % [@name]) if @socket.closed?
+      log_message("At least %d messages are not sent to the client." % 
+                  [@write_queue.get_messages.size])
     end # thread
-  rescue
-
   end
 
   #
   # Note that sending a message is included in the giant lock.
   #
   def write_safe(str)
-    @write_queue.enq str
+    @write_queue.enq(str)
   end
 
   def to_s
@@ -247,7 +251,7 @@ class Player < BasicPlayer
           @socket_buffer << str
           str = @socket_buffer.shift
         end
-        log_message("%s (%s)" % [str, @socket_buffer.map {|a| String === a ? a.strip : a }.join(",")]) if $DEBUG
+        log_debug("%s (%s)" % [str, @socket_buffer.map {|a| String === a ? a.strip : a }.join(",")])
 
         if (csa_1st_str)
           str = csa_1st_str
@@ -305,27 +309,27 @@ class Player < BasicPlayer
           end
         when /^%%SHOW\s+(\S+)/
           game_id = $1
-          if (LEAGUE.games[game_id])
-            write_safe(LEAGUE.games[game_id].show.gsub(/^/, '##[SHOW] '))
+          if ($league.games[game_id])
+            write_safe($league.games[game_id].show.gsub(/^/, '##[SHOW] '))
           end
           write_safe("##[SHOW] +OK\n")
         when /^%%MONITORON\s+(\S+)/
           game_id = $1
-          if (LEAGUE.games[game_id])
-            LEAGUE.games[game_id].monitoron(self)
-            write_safe(LEAGUE.games[game_id].show.gsub(/^/, "##[MONITOR][#{game_id}] "))
+          if ($league.games[game_id])
+            $league.games[game_id].monitoron(self)
+            write_safe($league.games[game_id].show.gsub(/^/, "##[MONITOR][#{game_id}] "))
             write_safe("##[MONITOR][#{game_id}] +OK\n")
           end
         when /^%%MONITOROFF\s+(\S+)/
           game_id = $1
-          if (LEAGUE.games[game_id])
-            LEAGUE.games[game_id].monitoroff(self)
+          if ($league.games[game_id])
+            $league.games[game_id].monitoroff(self)
           end
         when /^%%HELP/
           write_safe(
             %!##[HELP] available commands "%%WHO", "%%CHAT str", "%%GAME game_name +", "%%GAME game_name -"\n!)
         when /^%%RATING/
-          players = LEAGUE.rated_players
+          players = $league.rated_players
           players.sort {|a,b| b.rate <=> a.rate}.each do |p|
             write_safe("##[RATING] %s \t %4d @%s\n" % 
                        [p.simple_player_id, p.rate, p.modified_at.strftime("%Y-%m-%d")])
@@ -364,11 +368,11 @@ class Player < BasicPlayer
             @sente = nil
           else
             if (my_sente_str == "*")
-              rival = LEAGUE.get_player("game_waiting", game_name, nil, self) # no preference
+              rival = $league.get_player("game_waiting", game_name, nil, self) # no preference
             elsif (my_sente_str == "+")
-              rival = LEAGUE.get_player("game_waiting", game_name, false, self) # rival must be gote
+              rival = $league.get_player("game_waiting", game_name, false, self) # rival must be gote
             elsif (my_sente_str == "-")
-              rival = LEAGUE.get_player("game_waiting", game_name, true, self) # rival must be sente
+              rival = $league.get_player("game_waiting", game_name, true, self) # rival must be sente
             else
               ## never reached
               write_safe(sprintf("##[ERROR] bad game option\n"))
@@ -420,21 +424,21 @@ class Player < BasicPlayer
           end
         when /^%%CHAT\s+(.+)/
           message = $1
-          LEAGUE.players.each do |name, player|
+          $league.players.each do |name, player|
             if (player.protocol != LoginCSA::PROTOCOL)
               player.write_safe(sprintf("##[CHAT][%s] %s\n", @name, message)) 
             end
           end
         when /^%%LIST/
           buf = Array::new
-          LEAGUE.games.each do |id, game|
+          $league.games.each do |id, game|
             buf.push(sprintf("##[LIST] %s\n", id))
           end
           buf.push("##[LIST] +OK\n")
           write_safe(buf.join)
         when /^%%WHO/
           buf = Array::new
-          LEAGUE.players.each do |name, player|
+          $league.players.each do |name, player|
             buf.push(sprintf("##[WHO] %s\n", player.to_s))
           end
           buf.push("##[WHO] +OK\n")