refactor: implement s3 storage

This commit is contained in:
Steven
2024-05-02 21:28:06 +08:00
parent 355ea352aa
commit 26545c855c
55 changed files with 842 additions and 858 deletions

View File

@@ -6,66 +6,76 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/aws"
s3config "github.com/aws/aws-sdk-go-v2/config"
"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"
awss3 "github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/pkg/errors"
storepb "github.com/usememos/memos/proto/gen/store"
)
const LinkLifetime = 24 * time.Hour
type Config struct {
AccessKeyID string
AcesssKeySecret string
Endpoint string
Region string
Bucket string
}
const presignLifetimeSecs = 7 * 24 * 60 * 60
type Client struct {
Client *awss3.Client
Config *Config
Client *s3.Client
Bucket *string
}
func NewClient(ctx context.Context, config *Config) (*Client, error) {
func NewClient(ctx context.Context, s3Config *storepb.WorkspaceStorageSetting_S3Config) (*Client, error) {
resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...any) (aws.Endpoint, error) {
return aws.Endpoint{
URL: config.Endpoint,
URL: s3Config.Endpoint,
}, nil
})
s3Config, err := s3config.LoadDefaultConfig(ctx,
s3config.WithEndpointResolverWithOptions(resolver),
s3config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(config.AccessKeyID, config.AcesssKeySecret, "")),
s3config.WithRegion(config.Region),
cfg, err := config.LoadDefaultConfig(ctx,
config.WithEndpointResolverWithOptions(resolver),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(s3Config.AccessKeyId, s3Config.AccessKeySecret, "")),
config.WithRegion(s3Config.Region),
)
if err != nil {
return nil, errors.Wrap(err, "failed to load s3 config")
}
client := awss3.NewFromConfig(s3Config)
client := s3.NewFromConfig(cfg)
return &Client{
Client: client,
Config: config,
Bucket: aws.String(s3Config.Bucket),
}, nil
}
func (client *Client) UploadFile(ctx context.Context, filename string, fileType string, src io.Reader) (string, error) {
// UploadObject uploads an object to S3.
func (client *Client) UploadObject(ctx context.Context, key string, fileType string, content io.Reader) (string, error) {
uploader := manager.NewUploader(client.Client)
putInput := awss3.PutObjectInput{
Bucket: aws.String(client.Config.Bucket),
Key: aws.String(filename),
Body: src,
putInput := s3.PutObjectInput{
Bucket: client.Bucket,
Key: aws.String(key),
ContentType: aws.String(fileType),
Body: content,
}
uploadOutput, err := uploader.Upload(ctx, &putInput)
result, err := uploader.Upload(ctx, &putInput)
if err != nil {
return "", err
}
link := uploadOutput.Location
if link == "" {
return "", errors.New("failed to get file link")
resultKey := result.Key
if resultKey == nil || *resultKey == "" {
return "", errors.New("failed to get file key")
}
return link, nil
return *resultKey, nil
}
// PresignGetObject presigns an object in S3.
func (client *Client) PresignGetObject(ctx context.Context, bucket, key string) (string, error) {
presignClient := s3.NewPresignClient(client.Client)
presignResult, err := presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
}, func(opts *s3.PresignOptions) {
opts.Expires = time.Duration(presignLifetimeSecs * int64(time.Second))
})
if err != nil {
return "", errors.Wrap(err, "failed to presign put object")
}
return presignResult.URL, nil
}