etehtsea/oxblood

View on GitHub
lib/oxblood/connection.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'oxblood/protocol'
require 'oxblood/pipeline'
require 'oxblood/rsocket'
require 'oxblood/session'

module Oxblood
  # Class responsible for connection maintenance
  class Connection
    # @!attribute [r] socket
    #   @return [RSocket] resilient socket
    attr_reader :socket

    # @!attribute [rw] transaction_mode
    #   @return [Boolean] transaction status
    # @api private
    attr_accessor :transaction_mode

    # Initialize connection to Redis server
    #
    # @param [Hash] opts Connection options
    #
    # @option opts [Float] :timeout (1.0) socket read/write timeout
    # @option opts [Integer] :db database number
    # @option opts [String] :password
    #
    # @option opts [String] :host ('localhost') Hostname or IP address to connect to
    # @option opts [Integer] :port (6379) Port Redis server listens on
    # @option opts [Float] :connect_timeout (1.0) socket connect timeout
    #
    # @option opts [String] :path UNIX socket path
    def initialize(opts = {})
      @in_transaction = false
      @socket = RSocket.new(opts)

      session = Session.new(self)
      session.auth(opts[:password]) if opts[:password]
      session.select(opts[:db]) if opts[:db]
    end

    # Send comand to Redis server
    # @example
    #   send_command('CONFIG', 'GET', '*') => 32
    #
    # @param [Array] command Array of command name with it's args
    #
    # @return [Integer] Number of bytes written to socket
    def send_command(*command)
      @socket.write(Protocol.build_command(*command))
    end

    # Send command to Redis server and read response from it
    # @example run_command('PING') => PONG
    # @param [Array] command Array of command name with it's args
    def run_command(*command)
      send_command(*command)
      read_response
    end

    # Read response from server
    # @raise [RSocket::TimeoutError] if timeout happen
    # @note Will raise RSocket::TimeoutError even if there is simply no response to read
    #       from server. For example, if you are trying to read response before
    #       sending command.
    # @todo Raise specific error if server has nothing to answer.
    def read_response
      Protocol.parse(@socket)
    end

    # Connection transaction status.
    # @api private
    #
    # @return [Boolean, nil] transaction status
    def in_transaction?
      transaction_mode
    end
  end
end