|
|
|
@ -12,7 +12,6 @@ import (
|
|
|
|
|
"sync"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/Mikubill/gofakes3"
|
|
|
|
|
"github.com/alist-org/alist/v3/internal/errs"
|
|
|
|
|
"github.com/alist-org/alist/v3/internal/fs"
|
|
|
|
|
"github.com/alist-org/alist/v3/internal/model"
|
|
|
|
@ -20,12 +19,13 @@ import (
|
|
|
|
|
"github.com/alist-org/alist/v3/internal/stream"
|
|
|
|
|
"github.com/alist-org/alist/v3/pkg/http_range"
|
|
|
|
|
"github.com/alist-org/alist/v3/pkg/utils"
|
|
|
|
|
"github.com/alist-org/gofakes3"
|
|
|
|
|
"github.com/ncw/swift/v2"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
emptyPrefix = &gofakes3.Prefix{}
|
|
|
|
|
timeFormat = "Mon, 2 Jan 2006 15:04:05.999999999 GMT"
|
|
|
|
|
timeFormat = "Mon, 2 Jan 2006 15:04:05 GMT"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// s3Backend implements the gofacess3.Backend interface to make an S3
|
|
|
|
@ -42,13 +42,12 @@ func newBackend() gofakes3.Backend {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ListBuckets always returns the default bucket.
|
|
|
|
|
func (b *s3Backend) ListBuckets() ([]gofakes3.BucketInfo, error) {
|
|
|
|
|
func (b *s3Backend) ListBuckets(ctx context.Context) ([]gofakes3.BucketInfo, error) {
|
|
|
|
|
buckets, err := getAndParseBuckets()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
var response []gofakes3.BucketInfo
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
for _, b := range buckets {
|
|
|
|
|
node, _ := fs.Get(ctx, b.Path, &fs.GetArgs{})
|
|
|
|
|
response = append(response, gofakes3.BucketInfo{
|
|
|
|
@ -61,7 +60,7 @@ func (b *s3Backend) ListBuckets() ([]gofakes3.BucketInfo, error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ListBucket lists the objects in the given bucket.
|
|
|
|
|
func (b *s3Backend) ListBucket(bucketName string, prefix *gofakes3.Prefix, page gofakes3.ListBucketPage) (*gofakes3.ObjectList, error) {
|
|
|
|
|
func (b *s3Backend) ListBucket(ctx context.Context, bucketName string, prefix *gofakes3.Prefix, page gofakes3.ListBucketPage) (*gofakes3.ObjectList, error) {
|
|
|
|
|
bucket, err := getBucketByName(bucketName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
@ -97,8 +96,7 @@ func (b *s3Backend) ListBucket(bucketName string, prefix *gofakes3.Prefix, page
|
|
|
|
|
// HeadObject returns the fileinfo for the given object name.
|
|
|
|
|
//
|
|
|
|
|
// Note that the metadata is not supported yet.
|
|
|
|
|
func (b *s3Backend) HeadObject(bucketName, objectName string) (*gofakes3.Object, error) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
func (b *s3Backend) HeadObject(ctx context.Context, bucketName, objectName string) (*gofakes3.Object, error) {
|
|
|
|
|
bucket, err := getBucketByName(bucketName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
@ -141,8 +139,7 @@ func (b *s3Backend) HeadObject(bucketName, objectName string) (*gofakes3.Object,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetObject fetchs the object from the filesystem.
|
|
|
|
|
func (b *s3Backend) GetObject(bucketName, objectName string, rangeRequest *gofakes3.ObjectRangeRequest) (obj *gofakes3.Object, err error) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
func (b *s3Backend) GetObject(ctx context.Context, bucketName, objectName string, rangeRequest *gofakes3.ObjectRangeRequest) (obj *gofakes3.Object, err error) {
|
|
|
|
|
bucket, err := getBucketByName(bucketName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
@ -251,18 +248,17 @@ func (b *s3Backend) GetObject(bucketName, objectName string, rangeRequest *gofak
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TouchObject creates or updates meta on specified object.
|
|
|
|
|
func (b *s3Backend) TouchObject(fp string, meta map[string]string) (result gofakes3.PutObjectResult, err error) {
|
|
|
|
|
func (b *s3Backend) TouchObject(ctx context.Context, fp string, meta map[string]string) (result gofakes3.PutObjectResult, err error) {
|
|
|
|
|
//TODO: implement
|
|
|
|
|
return result, gofakes3.ErrNotImplemented
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PutObject creates or overwrites the object with the given name.
|
|
|
|
|
func (b *s3Backend) PutObject(
|
|
|
|
|
bucketName, objectName string,
|
|
|
|
|
ctx context.Context, bucketName, objectName string,
|
|
|
|
|
meta map[string]string,
|
|
|
|
|
input io.Reader, size int64,
|
|
|
|
|
) (result gofakes3.PutObjectResult, err error) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
bucket, err := getBucketByName(bucketName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return result, err
|
|
|
|
@ -316,9 +312,9 @@ func (b *s3Backend) PutObject(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteMulti deletes multiple objects in a single request.
|
|
|
|
|
func (b *s3Backend) DeleteMulti(bucketName string, objects ...string) (result gofakes3.MultiDeleteResult, rerr error) {
|
|
|
|
|
func (b *s3Backend) DeleteMulti(ctx context.Context, bucketName string, objects ...string) (result gofakes3.MultiDeleteResult, rerr error) {
|
|
|
|
|
for _, object := range objects {
|
|
|
|
|
if err := b.deleteObject(bucketName, object); err != nil {
|
|
|
|
|
if err := b.deleteObject(ctx, bucketName, object); err != nil {
|
|
|
|
|
utils.Log.Errorf("serve s3", "delete object failed: %v", err)
|
|
|
|
|
result.Error = append(result.Error, gofakes3.ErrorResult{
|
|
|
|
|
Code: gofakes3.ErrInternal,
|
|
|
|
@ -336,13 +332,12 @@ func (b *s3Backend) DeleteMulti(bucketName string, objects ...string) (result go
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteObject deletes the object with the given name.
|
|
|
|
|
func (b *s3Backend) DeleteObject(bucketName, objectName string) (result gofakes3.ObjectDeleteResult, rerr error) {
|
|
|
|
|
return result, b.deleteObject(bucketName, objectName)
|
|
|
|
|
func (b *s3Backend) DeleteObject(ctx context.Context, bucketName, objectName string) (result gofakes3.ObjectDeleteResult, rerr error) {
|
|
|
|
|
return result, b.deleteObject(ctx, bucketName, objectName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deleteObject deletes the object from the filesystem.
|
|
|
|
|
func (b *s3Backend) deleteObject(bucketName, objectName string) error {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
func (b *s3Backend) deleteObject(ctx context.Context, bucketName, objectName string) error {
|
|
|
|
|
bucket, err := getBucketByName(bucketName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
@ -362,17 +357,17 @@ func (b *s3Backend) deleteObject(bucketName, objectName string) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateBucket creates a new bucket.
|
|
|
|
|
func (b *s3Backend) CreateBucket(name string) error {
|
|
|
|
|
func (b *s3Backend) CreateBucket(ctx context.Context, name string) error {
|
|
|
|
|
return gofakes3.ErrNotImplemented
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteBucket deletes the bucket with the given name.
|
|
|
|
|
func (b *s3Backend) DeleteBucket(name string) error {
|
|
|
|
|
func (b *s3Backend) DeleteBucket(ctx context.Context, name string) error {
|
|
|
|
|
return gofakes3.ErrNotImplemented
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BucketExists checks if the bucket exists.
|
|
|
|
|
func (b *s3Backend) BucketExists(name string) (exists bool, err error) {
|
|
|
|
|
func (b *s3Backend) BucketExists(ctx context.Context, name string) (exists bool, err error) {
|
|
|
|
|
buckets, err := getAndParseBuckets()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
@ -386,13 +381,12 @@ func (b *s3Backend) BucketExists(name string) (exists bool, err error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CopyObject copy specified object from srcKey to dstKey.
|
|
|
|
|
func (b *s3Backend) CopyObject(srcBucket, srcKey, dstBucket, dstKey string, meta map[string]string) (result gofakes3.CopyObjectResult, err error) {
|
|
|
|
|
func (b *s3Backend) CopyObject(ctx context.Context, srcBucket, srcKey, dstBucket, dstKey string, meta map[string]string) (result gofakes3.CopyObjectResult, err error) {
|
|
|
|
|
if srcBucket == dstBucket && srcKey == dstKey {
|
|
|
|
|
//TODO: update meta
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
srcB, err := getBucketByName(srcBucket)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return result, err
|
|
|
|
@ -403,7 +397,7 @@ func (b *s3Backend) CopyObject(srcBucket, srcKey, dstBucket, dstKey string, meta
|
|
|
|
|
fmeta, _ := op.GetNearestMeta(srcFp)
|
|
|
|
|
srcNode, err := fs.Get(context.WithValue(ctx, "meta", fmeta), srcFp, &fs.GetArgs{})
|
|
|
|
|
|
|
|
|
|
c, err := b.GetObject(srcBucket, srcKey, nil)
|
|
|
|
|
c, err := b.GetObject(ctx, srcBucket, srcKey, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@ -420,7 +414,7 @@ func (b *s3Backend) CopyObject(srcBucket, srcKey, dstBucket, dstKey string, meta
|
|
|
|
|
meta["mtime"] = swift.TimeToFloatString(srcNode.ModTime())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, err = b.PutObject(dstBucket, dstKey, meta, c.Contents, c.Size)
|
|
|
|
|
_, err = b.PutObject(ctx, dstBucket, dstKey, meta, c.Contents, c.Size)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|