robotfs/utils/s3ReadSeeker.go

83 lines
1.5 KiB
Go

package utils
import (
"fmt"
"io"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
)
type S3ReadSeeker struct {
client *s3.S3
bucket string
key string
offset int64
body io.ReadCloser
contentLen int64
}
func NewS3ReadSeeker(client *s3.S3, bucket, key string, body io.ReadCloser, contentLen int64) *S3ReadSeeker {
return &S3ReadSeeker{
client: client,
bucket: bucket,
key: key,
body: body,
contentLen: contentLen,
}
}
func (r *S3ReadSeeker) Read(p []byte) (n int, err error) {
if r.body == nil {
return 0, io.EOF
}
return r.body.Read(p)
}
func (r *S3ReadSeeker) Seek(offset int64, whence int) (int64, error) {
if r.body != nil {
r.body.Close()
r.body = nil
}
var newOffset int64
switch whence {
case io.SeekStart:
newOffset = offset
case io.SeekCurrent:
newOffset = r.offset + offset
case io.SeekEnd:
newOffset = r.contentLen + offset
default:
return 0, fmt.Errorf("invalid whence")
}
if newOffset < 0 {
return 0, fmt.Errorf("negative offset")
}
if newOffset >= r.contentLen {
return r.contentLen, nil
}
result, err := r.client.GetObject(&s3.GetObjectInput{
Bucket: aws.String(r.bucket),
Key: aws.String(r.key),
Range: aws.String(fmt.Sprintf("bytes=%d-", newOffset)),
})
if err != nil {
return 0, err
}
r.body = result.Body
r.offset = newOffset
return newOffset, nil
}
func (r *S3ReadSeeker) Close() error {
if r.body != nil {
return r.body.Close()
}
return nil
}