mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
refactor: implement s3 storage
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user