class TransmissionChaos::Client

Constants

UPDATE_INTERVAL

Attributes

proxy_uri[RW]
read_timeout[RW]
target_percent[RW]
url[RW]
validate_certificate[RW]

Public Class Methods

new(url, target_percent: 10, **params) click to toggle source
# File lib/transmission_chaos/client.rb, line 12
def initialize(url, target_percent: 10, **params)
  url = URI.parse(url) unless url.is_a? URI

  @url = url
  @url.path = '/transmission/rpc'

  @validate_certificate = params[:validate_certificate]
  @proxy_uri = params[:proxy_uri]
  @read_timeout = params.fetch(:read_timeout, 30)
  @target_percent = target_percent.to_f

  @torrents_updated = Time.new(0)
end

Public Instance Methods

add_chaos() click to toggle source
# File lib/transmission_chaos/client.rb, line 30
def add_chaos
  running = torrents.select(&:active?)
  ready_for_more = torrents.select { |t| t.stopped? && !t.errored? }

  return unless ready_for_more.any?

  running_perc = running.count.to_f / torrents.count.to_f

  if running_perc < (target_percent / 100.0)
    logger.info "Less than 10% active (#{running.count}/#{torrents.count} | #{(running_perc * 100).to_i}%), starting some more"

    to_start = ready_for_more.sample(5)

    logger.info "Adding chaos with:\n- #{to_start.map(&:name).join("\n- ")}"

    rpc_call('torrent-start', ids: to_start.map(&:id))
  else
    logger.info "Transmission currently in chaos. (#{running.count}/#{torrents.count} | #{(running_perc * 100).to_i}% active)"
  end
end
logger() click to toggle source
# File lib/transmission_chaos/client.rb, line 26
def logger
  @logger ||= ::Logging.logger[self]
end
rpc_call(method, **arguments) click to toggle source
# File lib/transmission_chaos/client.rb, line 61
def rpc_call(method, **arguments)
  req = Net::HTTP::Post.new url
  req.body = { method: method, arguments: arguments }.to_json
  req.content_type = 'application/json'
  req.content_length = req.body.size
  req['x-transmission-session-id'] = @session_id if @session_id

  loop do
    print_http(req)
    begin
      response = http.request req
    rescue EOFError => e
      logger.error 'Socket closed unexpectedly'
      raise e
    end
    print_http(response)

    if response.is_a? Net::HTTPConflict
      @session_id = response['x-transmission-session-id']
      req['x-transmission-session-id'] = @session_id
    else
      data = JSON.parse(response.body, symbolize_names: true) rescue nil

      return data[:arguments]
    end
  end
end
torrents() click to toggle source
# File lib/transmission_chaos/client.rb, line 51
def torrents
  @torrents = nil if Time.now - @torrents_updated > UPDATE_INTERVAL

  @torrents ||= begin
    data = rpc_call('torrent-get', fields: %i[id error name status])
    @torrents_updated = Time.now
    data[:torrents].map { |t| Torrent.new(**t) }
  end
end

Private Instance Methods

http() click to toggle source
# File lib/transmission_chaos/client.rb, line 112
def http
  return @http if @http&.active?

  host = (@connection_address || url.host)
  port = (@connection_port || url.port)
  @http ||= if proxy_uri
              Net::HTTP.new(host, port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
            else
              Net::HTTP.new(host, port)
            end

  @http.read_timeout = read_timeout
  @http.use_ssl = url.scheme == 'https'
  @http.verify_mode = validate_certificate ? ::OpenSSL::SSL::VERIFY_NONE : nil
  @http.start
  @http
end
print_http(http) click to toggle source