class Google::Apis::Core::DownloadCommand
Streaming/resumable media download support
Constants
- OK_STATUS
- RANGE_HEADER
Attributes
File or IO to write content to @return [String, File, write]
Public Instance Methods
Execute the upload request once. Overrides the default implementation to handle streaming/chunking of file content.
@private @param [HTTPClient] client
HTTP client
@yield [result, err] Result or error if block supplied @return [Object] @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification @raise [Google::Apis::AuthorizationError] Authorization is required
# File lib/google/apis/core/download.rb, line 71 def execute_once(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 @download_io.respond_to?(: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, &block) rescue => e @download_io.flush if @download_io.respond_to?(:flush) error(e, rethrow: true, &block) end
Ensure the download destination is a writable stream.
@return [void]
Google::Apis::Core::ApiCommand#prepare!
# File lib/google/apis/core/download.rb, line 35 def prepare! @state = :start @download_url = nil @offset = 0 if @download_dest.is_a?(Pathname) @download_io = File.open(download_dest, 'wb') @close_io_on_finish = true elsif download_dest.respond_to?(:write) @download_io = download_dest @close_io_on_finish = false elsif download_dest.is_a?(String) @download_io = File.open(download_dest, 'wb') @close_io_on_finish = true else @download_io = StringIO.new('', 'wb') @close_io_on_finish = false end super end
Close IO stream when command done. Only closes the stream if it was opened by the command.
# File lib/google/apis/core/download.rb, line 56 def release! @download_io.close if @close_io_on_finish end