golang-lib/web/file/s3/fs.go

88 lines
2.0 KiB
Go

/*
Package s3 implements a non-hierarchical file store using Amazon s3. A file
store uses a single bucket. Each file is an object with its UUID as the name.
The file name is stored in the user-defined object metadata x-amz-meta-filename.
*/
package s3
import (
"context"
"errors"
"io"
"io/fs"
"github.com/google/uuid"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
type FS struct {
client *minio.Client
bucket string
}
// New ``connects'' to an s3 endpoint and creates a file store using the
// specified bucket. The bucket is created if it doesn't exist.
func New(endpoint string, secure bool, id, secret, bucket, location string) (*FS, error) {
var fs FS
var err error
fs.client, err = minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(id, secret, ""),
Secure: secure,
})
if err != nil {
return nil, err
}
ctx := context.TODO()
err = fs.client.MakeBucket(ctx, bucket, minio.MakeBucketOptions{
Region: location,
})
if err != nil {
if exists, err := fs.client.BucketExists(ctx, bucket); err != nil || !exists {
return nil, err
}
}
fs.bucket = bucket
return &fs, nil
}
func (fs *FS) Store(id uuid.UUID, name, contentType string, data io.Reader) error {
ctx := context.TODO()
_, err := fs.client.PutObject(ctx, fs.bucket, id.String(), data, -1, minio.PutObjectOptions{
UserMetadata: map[string]string{
"filename": name,
},
ContentType: contentType,
})
return err
}
func (fs *FS) RemoveUUID(id uuid.UUID) error {
ctx := context.TODO()
return fs.client.RemoveObject(ctx, fs.bucket, id.String(), minio.RemoveObjectOptions{})
}
// TODO: implement
func (fs *FS) Open(name string) (fs.File, error) {
return nil, errors.New("not implemented")
}
func (fs *FS) OpenUUID(id uuid.UUID) (fs.File, error) {
ctx := context.TODO()
object, err := fs.client.GetObject(ctx, fs.bucket, id.String(), minio.GetObjectOptions{})
if err != nil {
return nil, err
}
return File{Object: object}, nil
}
// TODO: do some checking
func (fs *FS) Check() error {
return nil
}