rclone/vendor/storj.io/uplink/private/stream/download.go
Caleb Case a4f1f3d4e8 backend/tardigrade: Upgrade uplink to v1.0.7
This fixes a regression in the rclone tests from the v1.0.6 upgrade of
uplink. The failure was due to an improperly converted error resulting
in the wrong type of error.
2020-06-05 10:51:33 +01:00

118 lines
2.5 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package stream
import (
"context"
"io"
"storj.io/common/storj"
"storj.io/uplink/private/metainfo/kvmetainfo"
"storj.io/uplink/private/storage/streams"
)
// Download implements Reader, Seeker and Closer for reading from stream.
type Download struct {
ctx context.Context
stream kvmetainfo.ReadOnlyStream
streams streams.Store
reader io.ReadCloser
offset int64
limit int64
closed bool
}
// NewDownload creates new stream download.
func NewDownload(ctx context.Context, stream kvmetainfo.ReadOnlyStream, streams streams.Store) *Download {
return &Download{
ctx: ctx,
stream: stream,
streams: streams,
limit: stream.Info().Size,
}
}
// NewDownloadRange creates new stream range download with range from offset to offset+limit.
func NewDownloadRange(ctx context.Context, stream kvmetainfo.ReadOnlyStream, streams streams.Store, offset, limit int64) *Download {
if limit < 0 {
limit = stream.Info().Size - offset
}
return &Download{
ctx: ctx,
stream: stream,
streams: streams,
offset: offset,
limit: limit,
}
}
// Read reads up to len(data) bytes into data.
//
// If this is the first call it will read from the beginning of the stream.
// Use Seek to change the current offset for the next Read call.
//
// See io.Reader for more details.
func (download *Download) Read(data []byte) (n int, err error) {
if download.closed {
return 0, Error.New("already closed")
}
if download.reader == nil {
err = download.resetReader()
if err != nil {
return 0, err
}
}
if download.limit <= 0 {
return 0, io.EOF
}
if download.limit < int64(len(data)) {
data = data[:download.limit]
}
n, err = download.reader.Read(data)
download.limit -= int64(n)
download.offset += int64(n)
return n, err
}
// Close closes the stream and releases the underlying resources.
func (download *Download) Close() error {
if download.closed {
return Error.New("already closed")
}
download.closed = true
if download.reader == nil {
return nil
}
return download.reader.Close()
}
func (download *Download) resetReader() error {
if download.reader != nil {
err := download.reader.Close()
if err != nil {
return err
}
}
obj := download.stream.Info()
rr, err := download.streams.Get(download.ctx, storj.JoinPaths(obj.Bucket.Name, obj.Path), obj)
if err != nil {
return err
}
download.reader, err = rr.Range(download.ctx, download.offset, download.limit)
if err != nil {
return err
}
return nil
}