class IProto::TCPSocket

TODO: timeouts

Public Class Methods

new(host, port, reconnect = true) click to toggle source
# File lib/iproto/tcp_socket.rb, line 6
def initialize(host, port, reconnect = true)
  @addr = [host, port]
  @reconnect_timeout = Numeric === reconnect ? reconnect : DEFAULT_RECONNECT
  @reconnect = !!reconnect
  @socket = nil
  @reconnect_time = Time.now - 1
  @retry = true
end

Public Instance Methods

_raise_disconnected(message, _raise = true) click to toggle source
# File lib/iproto/tcp_socket.rb, line 84
def _raise_disconnected(message, _raise = true)
  old_socket = @socket
  if @reconnect
    @socket = nil
    @reconnect_time = Time.now + @reconnect_timeout
  else
    @socket = :disconnected
  end
  case _raise
  when true
    raise Disconnected, message
  when :retry
    begin
      # if request were sent, then we will not have EPIPE exception
      old_socket.send '\x00', 0
    rescue Errno::EPIPE
      # OS knows that socket is closed, and request were not sent
      raise Retry
    else
      # OS didn't notice socket is closed, request were sent probably
      raise Disconnected, message
    end
  end
end
close() click to toggle source
# File lib/iproto/tcp_socket.rb, line 15
def close
  @reconnect = false
  if @socket
    @socket.close rescue nil
    @socket = :disconnected
  end
end
connected?() click to toggle source
# File lib/iproto/tcp_socket.rb, line 23
def connected?
  @socket && @socket != :disconnected
end
could_be_connected?() click to toggle source
# File lib/iproto/tcp_socket.rb, line 27
def could_be_connected?
  @socket ? @socket != :disconnected
          : (@reconnect || @reconnect_time < Time.now)
end
recv_header(request_id) click to toggle source

end ConnectionAPI

# File lib/iproto/tcp_socket.rb, line 70
def recv_header(request_id)
  header = socket.read(HEADER_SIZE)  or _raise_disconnected('disconnected while read', @retry ? :retry : true)
  response_size = ::BinUtils.get_int32_le(header, 4)
  recv_request_id = ::BinUtils.get_int32_le(header, 8)
  unless request_id == recv_request_id
    raise UnexpectedResponse.new("Waiting response for request_id #{request_id}, but received for #{recv_request_id}")
  end
  response_size
end
recv_response(response_size) click to toggle source
# File lib/iproto/tcp_socket.rb, line 80
def recv_response(response_size)
  socket.read(response_size)  or _raise_disconnected('disconnected while read', true)
end
send_request(request_type, body) click to toggle source

begin ConnectionAPI

# File lib/iproto/tcp_socket.rb, line 53
def send_request(request_type, body)
  unless could_be_connected?
    raise Disconnected, "connection is closed"
  end
  begin
    request_id = next_request_id
    socket.send pack_request(request_type, request_id, body), 0
    response_size = recv_header request_id
    recv_response response_size
  rescue Errno::EPIPE, Retry => e
    _raise_disconnected(e, !@retry)
    @retry = false
    retry
  end
end
socket() click to toggle source
# File lib/iproto/tcp_socket.rb, line 32
def socket
  if (sock = @socket)
    sock != :disconnected ? sock : raise(Disconnected, "disconnected earlier")
  else
    sock = @socket = ::TCPSocket.new(*@addr)
    sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
    @retry = true
  end
  sock
rescue Errno::ECONNREFUSED => e
  unless @reconnect
    @socket = :disconnected
  else
    @reconnect_time = Time.now + @reconnect_timeout
  end
  raise CouldNotConnect, e
end