memos/plugin/storage/s3/s3.go

94 lines
2.6 KiB
Go
Raw Normal View History

package s3
import (
"context"
"io"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
2024-05-02 21:28:06 +08:00
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
2024-05-02 21:28:06 +08:00
"github.com/aws/aws-sdk-go-v2/service/s3"
2024-01-29 23:15:47 +08:00
"github.com/pkg/errors"
2024-05-02 21:28:06 +08:00
storepb "github.com/usememos/memos/proto/gen/store"
)
type Client struct {
2024-05-02 21:28:06 +08:00
Client *s3.Client
Bucket *string
}
2024-05-17 08:50:02 +08:00
func NewClient(ctx context.Context, s3Config *storepb.StorageS3Config) (*Client, error) {
resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...any) (aws.Endpoint, error) {
return aws.Endpoint{
2024-05-02 21:28:06 +08:00
URL: s3Config.Endpoint,
}, nil
})
2024-05-02 21:28:06 +08:00
cfg, err := config.LoadDefaultConfig(ctx,
config.WithEndpointResolverWithOptions(resolver),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(s3Config.AccessKeyId, s3Config.AccessKeySecret, "")),
config.WithRegion(s3Config.Region),
)
if err != nil {
2024-04-28 21:36:22 +08:00
return nil, errors.Wrap(err, "failed to load s3 config")
}
2024-05-02 21:28:06 +08:00
client := s3.NewFromConfig(cfg)
return &Client{
2023-02-24 00:02:51 +08:00
Client: client,
2024-05-02 21:28:06 +08:00
Bucket: aws.String(s3Config.Bucket),
}, nil
}
2024-05-02 21:28:06 +08:00
// UploadObject uploads an object to S3.
2024-05-02 21:44:17 +08:00
func (c *Client) UploadObject(ctx context.Context, key string, fileType string, content io.Reader) (string, error) {
uploader := manager.NewUploader(c.Client)
2024-05-02 21:28:06 +08:00
putInput := s3.PutObjectInput{
2024-05-02 21:44:17 +08:00
Bucket: c.Bucket,
2024-05-02 21:28:06 +08:00
Key: aws.String(key),
ContentType: aws.String(fileType),
2024-05-02 21:28:06 +08:00
Body: content,
}
2024-05-02 21:28:06 +08:00
result, err := uploader.Upload(ctx, &putInput)
if err != nil {
return "", err
}
2024-05-02 21:28:06 +08:00
resultKey := result.Key
if resultKey == nil || *resultKey == "" {
return "", errors.New("failed to get file key")
}
return *resultKey, nil
}
// PresignGetObject presigns an object in S3.
2024-05-02 21:44:17 +08:00
func (c *Client) PresignGetObject(ctx context.Context, key string) (string, error) {
presignClient := s3.NewPresignClient(c.Client)
2024-05-02 21:46:47 +08:00
presignResult, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
2024-05-02 21:44:17 +08:00
Bucket: aws.String(*c.Bucket),
2024-05-02 21:28:06 +08:00
Key: aws.String(key),
}, func(opts *s3.PresignOptions) {
2024-05-12 08:03:56 +08:00
// Set the expiration time of the presigned URL to 5 days.
// Reference: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
opts.Expires = time.Duration(5 * 24 * time.Hour)
2024-05-02 21:28:06 +08:00
})
if err != nil {
return "", errors.Wrap(err, "failed to presign put object")
2023-03-04 20:06:32 +08:00
}
2024-05-02 21:28:06 +08:00
return presignResult.URL, nil
}
2024-05-02 21:44:17 +08:00
// DeleteObject deletes an object in S3.
func (c *Client) DeleteObject(ctx context.Context, key string) error {
_, err := c.Client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: c.Bucket,
Key: aws.String(key),
})
if err != nil {
return errors.Wrap(err, "failed to delete object")
}
return nil
}