package s3 import ( "context" "fmt" "io" "github.com/aws/aws-sdk-go-v2/aws" "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/types" "github.com/usememos/memos/api" ) type Client struct { Client *awss3.Client BucketName string URLPrefix string } func NewClient(ctx context.Context, storage *api.Storage) (*Client, error) { resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: storage.EndPoint, SigningRegion: storage.Region, }, nil }) cfg, err := config.LoadDefaultConfig(ctx, config.WithEndpointResolverWithOptions(resolver), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(storage.AccessKey, storage.SecretKey, "")), ) if err != nil { return nil, err } client := awss3.NewFromConfig(cfg) return &Client{ Client: client, BucketName: storage.Bucket, URLPrefix: storage.URLPrefix, }, nil } func (client *Client) UploadFile(ctx context.Context, filename string, fileType string, src io.Reader, storage *api.Storage) (string, error) { uploader := manager.NewUploader(client.Client) resp, err := uploader.Upload(ctx, &awss3.PutObjectInput{ Bucket: aws.String(client.BucketName), Key: aws.String(filename), Body: src, ContentType: aws.String(fileType), ACL: types.ObjectCannedACL(*aws.String("public-read")), }) if err != nil { return "", err } var link string if storage.URLPrefix == "" { link = resp.Location } else { link = fmt.Sprintf("%s/%s", storage.URLPrefix, filename) } return link, nil }