OSDN Git Service

Added a new method, Player#wait_write_thread_finish, to have a writer thread finish...
[shogi-server/shogi-server.git] / shogi_server / player.rb
index f893c6f..08425f5 100644 (file)
@@ -30,7 +30,10 @@ class BasicPlayer
     @win  = 0
     @loss = 0
     @last_game_win = false
+    @rating_group = nil
+    @modified_at = nil
     @sente = nil
+    @game_name = ""
   end
 
   # Idetifier of the player in the rating system
@@ -60,6 +63,19 @@ class BasicPlayer
   # true for Sente; false for Gote
   attr_accessor :sente
 
+  # game name
+  attr_accessor :game_name
+
+  def is_human?
+    return [%r!_human$!, %r!_human@!].any? do |re|
+      re.match(@name)
+    end
+  end
+
+  def is_computer?
+    return !is_human?
+  end
+
   def modified_at
     @modified_at || Time.now
   end
@@ -99,6 +115,16 @@ class BasicPlayer
       @player_id = @password = nil
     end
   end
+
+  def set_sente_from_str(str)
+    case str
+    when "+" then @sente = true
+    when "-" then @sente = false
+    else
+      # str should be "*"
+      @sente = nil
+    end
+  end
 end
 
 
@@ -112,7 +138,6 @@ class Player < BasicPlayer
     @protocol = nil             # CSA or x1
     @eol = eol || "\m"          # favorite eol code
     @game = nil
-    @game_name = ""
     @mytime = 0                 # set in start method also
     @socket_buffer = []
     @main_thread = Thread::current
@@ -122,7 +147,7 @@ class Player < BasicPlayer
   end
 
   attr_accessor :socket, :status
-  attr_accessor :protocol, :eol, :game, :mytime, :game_name
+  attr_accessor :protocol, :eol, :game, :mytime
   attr_accessor :main_thread
   attr_reader :socket_buffer
   
@@ -179,8 +204,8 @@ class Player < BasicPlayer
         log_debug("Terminating %s's write thread..." % [@name])
         if @write_thread && @write_thread.alive?
           write_safe(nil)
+          Thread.pass # help the write_thread to terminate
         end
-        @player_logger.close if @player_logger
         log_debug("done.")
       rescue
         log_message(sprintf("user %s finish failed", @name))    
@@ -222,6 +247,17 @@ class Player < BasicPlayer
   end
 
   #
+  # Wait for the write thread to finish.
+  # This method should be called just before this instance will be freed.
+  #
+  def wait_write_thread_finish(msec=1000)
+    while msec > 0 && @write_thread && @write_thread.alive?
+      sleep 0.1; msec -= 0.1
+    end
+    @player_logger.close if @player_logger
+  end
+
+  #
   # Note that sending a message is included in the giant lock.
   #
   def write_safe(str)
@@ -245,6 +281,7 @@ class Player < BasicPlayer
   def run(csa_1st_str=nil)
     while ( csa_1st_str || 
             str = gets_safe(@socket, (@socket_buffer.empty? ? Default_Timeout : 1)) )
+      time = Time.now
       log(:info, :in, str) if str && str.instance_of?(String) 
       $mutex.lock
       begin
@@ -268,7 +305,11 @@ class Player < BasicPlayer
         end
         str.chomp! if (str.class == String) # may be strip! ?
 
-        cmd = ShogiServer::Command.factory(str, self)
+        delay = Time.now - time
+        if delay > 5
+          log_warning("Detected a long delay: %.2f sec" % [delay])
+        end
+        cmd = ShogiServer::Command.factory(str, self, time)
         case cmd.call
         when :return
           return
@@ -282,6 +323,7 @@ class Player < BasicPlayer
         $mutex.unlock
       end
     end # enf of while
+    log_warning("%s's socket was suddenly closed" % [@name])
   end # def run
 end # class