83 lines
1.5 KiB
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
|
|
}
|