No longer buffer chunks/files when using resumable upload
This commit is contained in:
parent
e27109078a
commit
903e568a65
|
@ -21,7 +21,11 @@ module Google
|
|||
# @see Faraday::UploadIO
|
||||
# @example
|
||||
# media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
|
||||
class UploadIO < Faraday::UploadIO
|
||||
class UploadIO < Faraday::UploadIO
|
||||
|
||||
# @return [Fixnum] Size of chunks to upload. Default is nil, meaning upload the entire file in a single request
|
||||
attr_accessor :chunk_size
|
||||
|
||||
##
|
||||
# Get the length of the stream
|
||||
#
|
||||
|
@ -32,6 +36,77 @@ module Google
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Wraps an input stream and limits data to a given range
|
||||
#
|
||||
# @example
|
||||
# chunk = Google::APIClient::RangedIO.new(io, 0, 1000)
|
||||
class RangedIO
|
||||
##
|
||||
# Bind an input stream to a specific range.
|
||||
#
|
||||
# @param [IO] io
|
||||
# Source input stream
|
||||
# @param [Fixnum] offset
|
||||
# Starting offset of the range
|
||||
# @param [Fixnum] length
|
||||
# Length of range
|
||||
def initialize(io, offset, length)
|
||||
@io = io
|
||||
@offset = offset
|
||||
@length = length
|
||||
self.rewind
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#read
|
||||
def read(amount = nil, buf = nil)
|
||||
buffer = buf || ''
|
||||
if amount.nil?
|
||||
size = @length - @pos
|
||||
done = ''
|
||||
elsif amount == 0
|
||||
size = 0
|
||||
done = ''
|
||||
else
|
||||
size = [@length - @pos, amount].min
|
||||
done = nil
|
||||
end
|
||||
|
||||
if size > 0
|
||||
result = @io.read(size)
|
||||
result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
|
||||
buffer << result if result
|
||||
@pos = @pos + size
|
||||
end
|
||||
|
||||
if buffer.length > 0
|
||||
buffer
|
||||
else
|
||||
done
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#rewind
|
||||
def rewind
|
||||
self.pos = 0
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#pos
|
||||
def pos
|
||||
@pos
|
||||
end
|
||||
|
||||
##
|
||||
# @see IO#pos=
|
||||
def pos=(pos)
|
||||
@pos = pos
|
||||
@io.pos = @offset + pos
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Resumable uploader.
|
||||
#
|
||||
|
@ -124,11 +199,11 @@ module Google
|
|||
'Content-Range' => "bytes */#{media.length}" })
|
||||
else
|
||||
start_offset = @offset
|
||||
self.media.io.pos = start_offset
|
||||
chunk = self.media.io.read(chunk_size)
|
||||
content_length = chunk.bytesize
|
||||
remaining = self.media.length - start_offset
|
||||
chunk_size = self.media.chunk_size || self.chunk_size || self.media.length
|
||||
content_length = [remaining, chunk_size].min
|
||||
chunk = RangedIO.new(self.media.io, start_offset, content_length)
|
||||
end_offset = start_offset + content_length - 1
|
||||
|
||||
self.headers.update({
|
||||
'Content-Length' => "#{content_length}",
|
||||
'Content-Type' => self.media.content_type,
|
||||
|
|
|
@ -165,7 +165,7 @@ module Google
|
|||
# Resumamble slightly different than other upload protocols in that it requires at least
|
||||
# 2 requests.
|
||||
if result.status == 200 && self.upload_type == 'resumable'
|
||||
upload = result.resumable_upload
|
||||
upload = result.resumable_upload
|
||||
unless upload.complete?
|
||||
logger.debug { "#{self.class} Sending upload body" }
|
||||
result = upload.send(connection)
|
||||
|
|
|
@ -57,6 +57,54 @@ describe Google::APIClient::UploadIO do
|
|||
end
|
||||
end
|
||||
|
||||
describe Google::APIClient::RangedIO do
|
||||
before do
|
||||
@source = StringIO.new("1234567890abcdef")
|
||||
@io = Google::APIClient::RangedIO.new(@source, 1, 5)
|
||||
end
|
||||
|
||||
it 'should return the correct range when read entirely' do
|
||||
@io.read.should == "23456"
|
||||
end
|
||||
|
||||
it 'should maintain position' do
|
||||
@io.read(1).should == '2'
|
||||
@io.read(2).should == '34'
|
||||
@io.read(2).should == '56'
|
||||
end
|
||||
|
||||
it 'should allow rewinds' do
|
||||
@io.read(2).should == '23'
|
||||
@io.rewind()
|
||||
@io.read(2).should == '23'
|
||||
end
|
||||
|
||||
it 'should allow setting position' do
|
||||
@io.pos = 3
|
||||
@io.read.should == '56'
|
||||
end
|
||||
|
||||
it 'should not allow position to be set beyond range' do
|
||||
@io.pos = 10
|
||||
@io.read.should == ''
|
||||
end
|
||||
|
||||
it 'should return empty string when read amount is zero' do
|
||||
@io.read(0).should == ''
|
||||
end
|
||||
|
||||
it 'should return empty string at EOF if amount is nil' do
|
||||
@io.read
|
||||
@io.read.should == ''
|
||||
end
|
||||
|
||||
it 'should return nil at EOF if amount is positive int' do
|
||||
@io.read
|
||||
@io.read(1).should == nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe Google::APIClient::ResumableUpload do
|
||||
CLIENT = Google::APIClient.new(:application_name => 'API Client Tests') unless defined?(CLIENT)
|
||||
|
||||
|
|
Loading…
Reference in New Issue