class DeathByCaptcha::Client::Socket

Socket client for DeathByCaptcha API.

Constants

PORTS

Public Instance Methods

captcha(captcha_id) click to toggle source

Retrieve information from an uploaded captcha.

@param [Integer] captcha_id Numeric ID of the captcha.

@return [DeathByCaptcha::Captcha] The captcha object.

# File lib/deathbycaptcha/client/socket.rb, line 15
def captcha(captcha_id)
  response = perform('captcha', captcha: captcha_id)
  DeathByCaptcha::Captcha.new(response)
end
report!(captcha_id) click to toggle source

Report incorrectly solved captcha for refund.

@param [Integer] captcha_id Numeric ID of the captcha.

@return [DeathByCaptcha::Captcha] The captcha object.

# File lib/deathbycaptcha/client/socket.rb, line 26
def report!(captcha_id)
  response = perform('report', captcha: captcha_id)
  DeathByCaptcha::Captcha.new(response)
end
status() click to toggle source

Retrieve DeathByCaptcha server status. This method won't use a Socket connection, it will use an HTTP connection.

@return [DeathByCaptcha::ServerStatus] The server status object.

# File lib/deathbycaptcha/client/socket.rb, line 45
def status
  http_client.status
end
upload(options = {}) click to toggle source

Upload a captcha to DeathByCaptcha.

This method will not return the solution. It's only useful if you want to implement your own “decode” function.

@return [DeathByCaptcha::Captcha] The captcha object (not solved yet).

# File lib/deathbycaptcha/client/socket.rb, line 56
def upload(options = {})
  if options[:type] && options[:type].to_i != 1
    # Socket client implementation currently supports only text captchas.
    raise DeathByCaptcha::InvalidCaptcha
  end
  response = perform('upload', captcha: options[:raw64])
  DeathByCaptcha::Captcha.new(response)
end
user() click to toggle source

Retrieve your user information (which has the current credit balance)

@return [DeathByCaptcha::User] The user object.

# File lib/deathbycaptcha/client/socket.rb, line 35
def user
  response = perform('user')
  DeathByCaptcha::User.new(response)
end

Private Instance Methods

create_socket() click to toggle source

Create a new socket connection with DeathByCaptcha API. This method is necessary because Ruby 1.9.7 doesn't support connection timeout and only Ruby 2.2.0 fixes a bug with unsafe sockets threads.

In Ruby >= 2.2.0, this could be implemented as simply as: ::Socket.tcp(HOST, PORTS.sample, connect_timeout: 0)

# File lib/deathbycaptcha/client/socket.rb, line 116
def create_socket
  socket = ::Socket.new(::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
  sockaddr = ::Socket.sockaddr_in(PORTS.sample, self.hostname)
  begin # emulate blocking connect
    socket.connect_nonblock(sockaddr)
  rescue IO::WaitWritable
    IO.select(nil, [socket]) # wait 3-way handshake completion
    begin
      socket.connect_nonblock(sockaddr) # check connection failure
    rescue Errno::EISCONN
    end
  end
  socket
end
http_client() click to toggle source

Return a cached http client for methods that doesn't work with sockets.

# File lib/deathbycaptcha/client/socket.rb, line 133
def http_client
  @http_client ||= DeathByCaptcha.new(self.username, self.password, :http)
end
perform(action, payload = {}) click to toggle source

Perform a Socket communication with the DeathByCaptcha API.

@param [String] action API method name. @param [Hash] payload Data to be exchanged in the communication.

@return [Hash] Response from the DeathByCaptcha API.

# File lib/deathbycaptcha/client/socket.rb, line 74
def perform(action, payload = {})
  payload.merge!(
    cmd: action,
    version: DeathByCaptcha::API_VERSION,
    username: self.username,
    password: self.password
  )

  socket = create_socket()
  socket.puts(payload.to_json)
  response = socket.read()
  socket.close()

  begin
    response = JSON.parse(response)
  rescue
    raise DeathByCaptcha::APIResponseError.new("invalid JSON: #{response}")
  end

  if !(error = response['error'].to_s).empty?
    case error
    when 'not-logged-in', 'invalid-credentials', 'banned', 'insufficient-funds'
      raise DeathByCaptcha::APIForbidden
    when 'invalid-captcha'
      raise DeathByCaptcha::APIBadRequest
    when 'service-overload'
      raise DeathByCaptcha::APIServiceUnavailable
    else
      raise DeathByCaptcha::APIResponseError.new(error)
    end
  end

  response
end