# server.rb
# $Id: server.rb,v 1.4 2005/03/07 07:51:32 komatsu Exp $
#
# Copyright (C) 2001 Satoru Takabayashi <satoru@namazu.org>
# Copyright (C) 2004 Hiroyuki Komatsu <komatsu@taiyaki.org>
#     All rights reserved.
#     This is free software with ABSOLUTELY NO WARRANTY.
#
# You can redistribute it and/or modify it under the terms of 
# the GNU General Public License version 2.
#

require 'socket'
require 'thread'

class Server
  def initialize (session)
    @session = session
    @iconv_out = nil
    @iconv_in  = nil
  end

  public
  def session_loop (io_in, io_out)
    loop {
      line = receive(io_in)
      if line.nil? then
        return  # The connection has been closed.
      end
      logging(line)
      Mutex.new.synchronize {
        result = @session.execute(line)
	if result then
	  send(io_out, result)
	else
	  return  # The connection has been closed.
	end
      }
      return if io_in.closed? or io_out.closed?
    }
  end

  ## This receives a string line from the PRIME session and returns it.
  ## If the session has been closed, this returns nil.
  def receive (io_in)
    line = @session.get_line(io_in)
    if line.nil? then
      return nil
    end

    if @iconv_in then
      begin
        return @iconv_in.iconv(line)
      rescue
        return nil
      end
    else
      return line
    end
  end

  def send (io_out, data)
    if @iconv_out then
      data = @iconv_out.iconv(data)
    end
    io_out.print(data)
  end

  def set_encoding (encoding)
    require 'iconv'
    @iconv_out = Iconv.new(encoding, "EUC-JP")  # PRIME -> Client
    @iconv_in  = Iconv.new("EUC-JP", encoding)  # PRIME <- Client
  end

  def set_debug ()
    @debug   = true
    Dir::ensure(PRIME_USER_DIR + "/logs")
    logfile = PRIME_USER_DIR + "/logs/debug_" +
              Time::new.strftime("%Y%m%d%H%M") + "_" + $$.to_s + ".log"
    @debug_io = File::open(logfile, "w")
    @debug_io.chmod(0600) if @debug_io::stat.owned?
  end

  ## This method writes Line to @debug_io, if the debug mode is on.
  ## This doesn't return any value.
  def logging (line)
    if @debug then
      line.chomp()
      @debug_io.puts(line)
      @debug_io.flush()
    end
  end
end

class UnixSocketServer < Server
  def initialize (session, path)
    super(session)
    @server = UNIXServer.new(path)
  end

  def start
    loop {
      socket = @server.accept
      t = Thread.new {
        session_loop(socket, socket)
        socket.close()
      }
      t.abort_on_exception = true
    }
  end
end

class TaiyakiTCPServer < Server
  def initialize (session, port)
    super(session)
    @server = TCPServer.new(port)
  end

  def start
    loop {
      socket = @server.accept
      t = Thread.new {
        session_loop(socket, socket)
        socket.close()
      }
      t.abort_on_exception = true
    }
  end
end

class StdioServer < Server
  def initialize (session)
    super(session)
    $stdout.sync = true
  end

  def start
    session_loop($stdin, $stdout)
  end
end
