2023-02-13 14:36:48 +03:00
|
|
|
package s3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2023-06-03 09:38:28 +03:00
|
|
|
"strings"
|
2023-02-13 14:36:48 +03:00
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
2023-02-23 19:02:51 +03:00
|
|
|
s3config "github.com/aws/aws-sdk-go-v2/config"
|
2023-02-13 14:36:48 +03:00
|
|
|
"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"
|
|
|
|
)
|
|
|
|
|
2023-02-23 19:02:51 +03:00
|
|
|
type Config struct {
|
|
|
|
AccessKey string
|
|
|
|
SecretKey string
|
|
|
|
Bucket string
|
|
|
|
EndPoint string
|
|
|
|
Region string
|
|
|
|
URLPrefix string
|
2023-04-01 10:28:00 +03:00
|
|
|
URLSuffix string
|
2023-02-23 19:02:51 +03:00
|
|
|
}
|
|
|
|
|
2023-02-13 14:36:48 +03:00
|
|
|
type Client struct {
|
2023-02-23 19:02:51 +03:00
|
|
|
Client *awss3.Client
|
|
|
|
Config *Config
|
2023-02-13 14:36:48 +03:00
|
|
|
}
|
|
|
|
|
2023-02-23 19:02:51 +03:00
|
|
|
func NewClient(ctx context.Context, config *Config) (*Client, error) {
|
2023-06-03 09:38:28 +03:00
|
|
|
// For some s3-compatible object stores, converting the hostname is not required,
|
|
|
|
// and not setting this option will result in not being able to access the corresponding object store address.
|
|
|
|
// But Aliyun OSS should disable this option
|
|
|
|
hostnameImmutable := true
|
|
|
|
if strings.HasSuffix(config.EndPoint, "aliyuncs.com") {
|
|
|
|
hostnameImmutable = false
|
|
|
|
}
|
2023-03-18 17:34:22 +03:00
|
|
|
resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...any) (aws.Endpoint, error) {
|
2023-02-13 14:36:48 +03:00
|
|
|
return aws.Endpoint{
|
2023-06-03 09:38:28 +03:00
|
|
|
URL: config.EndPoint,
|
|
|
|
SigningRegion: config.Region,
|
|
|
|
HostnameImmutable: hostnameImmutable,
|
2023-02-13 14:36:48 +03:00
|
|
|
}, nil
|
|
|
|
})
|
|
|
|
|
2023-02-27 16:26:50 +03:00
|
|
|
awsConfig, err := s3config.LoadDefaultConfig(ctx,
|
2023-02-23 19:02:51 +03:00
|
|
|
s3config.WithEndpointResolverWithOptions(resolver),
|
|
|
|
s3config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(config.AccessKey, config.SecretKey, "")),
|
2023-02-13 14:36:48 +03:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-27 16:26:50 +03:00
|
|
|
client := awss3.NewFromConfig(awsConfig)
|
2023-02-13 14:36:48 +03:00
|
|
|
|
|
|
|
return &Client{
|
2023-02-23 19:02:51 +03:00
|
|
|
Client: client,
|
|
|
|
Config: config,
|
2023-02-13 14:36:48 +03:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2023-02-23 19:02:51 +03:00
|
|
|
func (client *Client) UploadFile(ctx context.Context, filename string, fileType string, src io.Reader) (string, error) {
|
2023-02-13 14:36:48 +03:00
|
|
|
uploader := manager.NewUploader(client.Client)
|
2023-02-27 16:26:50 +03:00
|
|
|
uploadOutput, err := uploader.Upload(ctx, &awss3.PutObjectInput{
|
2023-02-23 19:02:51 +03:00
|
|
|
Bucket: aws.String(client.Config.Bucket),
|
2023-03-06 15:04:19 +03:00
|
|
|
Key: aws.String(filename),
|
2023-02-13 14:36:48 +03:00
|
|
|
Body: src,
|
|
|
|
ContentType: aws.String(fileType),
|
|
|
|
ACL: types.ObjectCannedACL(*aws.String("public-read")),
|
|
|
|
})
|
|
|
|
if err != nil {
|
2023-02-15 17:54:46 +03:00
|
|
|
return "", err
|
2023-02-13 14:36:48 +03:00
|
|
|
}
|
2023-02-27 16:26:50 +03:00
|
|
|
|
|
|
|
link := uploadOutput.Location
|
2023-03-04 15:06:32 +03:00
|
|
|
// If url prefix is set, use it as the file link.
|
|
|
|
if client.Config.URLPrefix != "" {
|
2023-04-01 10:28:00 +03:00
|
|
|
link = fmt.Sprintf("%s/%s%s", client.Config.URLPrefix, filename, client.Config.URLSuffix)
|
2023-02-13 14:36:48 +03:00
|
|
|
}
|
2023-03-04 15:06:32 +03:00
|
|
|
if link == "" {
|
|
|
|
return "", fmt.Errorf("failed to get file link")
|
|
|
|
}
|
2023-02-15 17:54:46 +03:00
|
|
|
return link, nil
|
2023-02-13 14:36:48 +03:00
|
|
|
}
|