class FileDownloader::Service

Attributes

filepath[R]
logger[R]
url[R]

Public Class Methods

new(url, filepath, logger: nil) click to toggle source
# File lib/file_downloader/service.rb, line 9
def initialize(url, filepath, logger: nil)
  @url = url
  @filepath = filepath
  @retry_count = 0
  @logger = logger || Logger.new($stdout)
end

Public Instance Methods

execute() click to toggle source
# File lib/file_downloader/service.rb, line 16
def execute
  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)

  content_length = fetch_content_length(http, uri)
  raise NoResponseBodyError if content_length.to_i.zero?
  download_file(http, uri, content_length)
  filepath
end

Private Instance Methods

download_file(http, uri, content_length) click to toggle source
# File lib/file_downloader/service.rb, line 39
def download_file(http, uri, content_length)
  file = File.open(filepath, 'wb')

  retry_on_error do
    res = http.get(uri.request_uri, 'range' => "bytes=#{file.size}-#{content_length}") do |bytes|
      file << bytes
    end
    Status.check(res.code)
    raise NotEofError unless file.size == content_length.to_i
  end
ensure
  file&.close
end
fetch_content_length(http, uri) click to toggle source
# File lib/file_downloader/service.rb, line 30
def fetch_content_length(http, uri)
  http.use_ssl = true if uri.port == 443

  res = http.head(uri.request_uri)
  Status.check(res.code)
  header = res.to_hash
  header['content-length'][0]
end
retry_on_error(times: 10) { || ... } click to toggle source
# File lib/file_downloader/service.rb, line 53
def retry_on_error(times: 10)
  @retry_count += 1
  yield
rescue NotEofError
  if @retry_count < times
    logger.info "Connection closed: #{@retry_count} time retry"
    retry
  else
    logger.error 'Connection closed'
    raise
  end
end