Class: Google::Apis::Core::DownloadCommand

Inherits:
ApiCommand
  • Object
show all
Defined in:
lib/google/cloud/storage/service.rb

Overview

Streaming/resumable media download support

Instance Method Summary collapse

Instance Method Details

#execute_once_with_response(client, &block) ⇒ Object

Returns a two-element array containing:

  • The result that is the usual return type of #execute_once.
  • The http_resp.


660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
# File 'lib/google/cloud/storage/service.rb', line 660

def execute_once_with_response(client, &block)
  request_header = header.dup
  apply_request_options(request_header)
  download_offset = nil

  if @offset > 0
    logger.debug { sprintf('Resuming download from offset %d', @offset) }
    request_header[RANGE_HEADER] = sprintf('bytes=%d-', @offset)
  end

  http_res = client.get(url.to_s,
             query: query,
             header: request_header,
             follow_redirect: true) do |res, chunk|
    status = res.http_header.status_code.to_i
    next unless OK_STATUS.include?(status)

    download_offset ||= (status == 206 ? @offset : 0)
    download_offset  += chunk.bytesize

    if download_offset - chunk.bytesize == @offset
      next_chunk = chunk
    else
      # Oh no! Requested a chunk, but received the entire content
      chunk_index = @offset - (download_offset - chunk.bytesize)
      next_chunk = chunk.byteslice(chunk_index..-1)
      next if next_chunk.nil?
    end
    # logger.debug { sprintf('Writing chunk (%d bytes, %d total)', chunk.length, bytes_read) }
    @download_io.write(next_chunk)

    @offset += next_chunk.bytesize
  end

  @download_io.flush

  if @close_io_on_finish
    result = nil
  else
    result = @download_io
  end
  check_status(http_res.status.to_i, http_res.header, http_res.body)
  success([result, http_res], &block)
rescue => e
  @download_io.flush
  error(e, rethrow: true, &block)
end

#execute_with_response(client) ⇒ Object

Returns a two-element array containing:

  • The result that is the usual return type of #execute.
  • The http_resp from #execute_once.


625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
# File 'lib/google/cloud/storage/service.rb', line 625

def execute_with_response(client)
  prepare!
  begin
    Retriable.retriable tries: options.retries + 1,
                        base_interval: 1,
                        multiplier: 2,
                        on: RETRIABLE_ERRORS do |try|
      # This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
      # auth to be re-attempted without having to retry all sorts of other failures like
      # NotFound, etc
      auth_tries = (try == 1 && authorization_refreshable? ? 2 : 1)
      Retriable.retriable tries: auth_tries,
                          on: [Google::Apis::AuthorizationError, Signet::AuthorizationError],
                          on_retry: proc { |*| refresh_authorization } do
        execute_once_with_response(client).tap do |result|
          if block_given?
            yield result, nil
          end
        end
      end
    end
  rescue => e
    if block_given?
      yield nil, e
    else
      raise e
    end
  end
ensure
  release!
end