feat: optional S3-compatible storage for uploaded images, instead of the local upload directory
This commit is contained in:
1 parent
d752a61e52
commit
eb9bfabed5
23 files changed
+1962
-7
No files matched your search
@@ -0,0 +1,83 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type rangeOpener func(offset int64) (io.ReadCloser, context.CancelFunc, error)
|
||||
|
||||
type s3Reader struct {
|
||||
size int64
|
||||
position int64
|
||||
bodyOffset int64
|
||||
body io.ReadCloser
|
||||
cancel context.CancelFunc
|
||||
reopen rangeOpener
|
||||
}
|
||||
|
||||
func newS3Reader(size int64, body io.ReadCloser, cancel context.CancelFunc, reopen rangeOpener) *s3Reader {
|
||||
return &s3Reader{size: size, body: body, cancel: cancel, reopen: reopen}
|
||||
}
|
||||
|
||||
func (r *s3Reader) Read(p []byte) (int, error) {
|
||||
if r.position >= r.size {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if r.body == nil || r.bodyOffset != r.position {
|
||||
if err := r.openAtPosition(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
n, err := r.body.Read(p)
|
||||
r.position += int64(n)
|
||||
r.bodyOffset = r.position
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *s3Reader) openAtPosition() error {
|
||||
r.release()
|
||||
body, cancel, err := r.reopen(r.position)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.body, r.cancel, r.bodyOffset = body, cancel, r.position
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *s3Reader) Seek(offset int64, whence int) (int64, error) {
|
||||
var target int64
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
target = offset
|
||||
case io.SeekCurrent:
|
||||
target = r.position + offset
|
||||
case io.SeekEnd:
|
||||
target = r.size + offset
|
||||
default:
|
||||
return 0, errors.New("invalid seek whence")
|
||||
}
|
||||
if target < 0 {
|
||||
return 0, fmt.Errorf("negative seek position %d", target)
|
||||
}
|
||||
r.position = target
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (r *s3Reader) Close() error {
|
||||
r.release()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *s3Reader) release() {
|
||||
if r.body != nil {
|
||||
_ = r.body.Close()
|
||||
r.body = nil
|
||||
}
|
||||
if r.cancel != nil {
|
||||
r.cancel()
|
||||
r.cancel = nil
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user