mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-21 06:48:44 +08:00
* refactor: Migrate S3 client to AWS SDK v2 * refactor: Migrate S3 client to AWS SDK v2 and update dependencies * refactor: Simplify endpoint handling in S3 client initialization * refactor: Update S3 client method receivers to pointer types for consistency
182 lines
4.6 KiB
Go
182 lines
4.6 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"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"
|
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
|
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
|
"github.com/aws/smithy-go"
|
|
)
|
|
|
|
type s3Client struct {
|
|
scType string
|
|
bucket string
|
|
client *s3.Client
|
|
}
|
|
|
|
func NewS3Client(vars map[string]interface{}) (*s3Client, error) {
|
|
accessKey := loadParamFromVars("accessKey", vars)
|
|
secretKey := loadParamFromVars("secretKey", vars)
|
|
endpoint := loadParamFromVars("endpoint", vars)
|
|
region := loadParamFromVars("region", vars)
|
|
bucket := loadParamFromVars("bucket", vars)
|
|
scType := loadParamFromVars("scType", vars)
|
|
if len(scType) == 0 {
|
|
scType = "Standard"
|
|
}
|
|
mode := loadParamFromVars("mode", vars)
|
|
if len(mode) == 0 {
|
|
mode = "virtual hosted"
|
|
}
|
|
cfg, err := config.LoadDefaultConfig(context.Background(),
|
|
config.WithRegion(region),
|
|
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
|
|
o.UsePathStyle = mode == "path"
|
|
if endpoint != "" {
|
|
o.BaseEndpoint = aws.String(normalizeEndpoint(endpoint))
|
|
}
|
|
})
|
|
|
|
return &s3Client{scType: scType, bucket: bucket, client: client}, nil
|
|
}
|
|
|
|
func (s *s3Client) ListBuckets() ([]interface{}, error) {
|
|
var result []interface{}
|
|
res, err := s.client.ListBuckets(context.Background(), &s3.ListBucketsInput{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, b := range res.Buckets {
|
|
result = append(result, b.Name)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (s *s3Client) Exist(path string) (bool, error) {
|
|
_, err := s.client.HeadObject(context.Background(), &s3.HeadObjectInput{
|
|
Bucket: aws.String(s.bucket),
|
|
Key: aws.String(path),
|
|
})
|
|
if err != nil {
|
|
var apiErr smithy.APIError
|
|
if errors.As(err, &apiErr) {
|
|
switch apiErr.ErrorCode() {
|
|
case "NotFound", "NoSuchKey":
|
|
return false, nil
|
|
}
|
|
}
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *s3Client) Size(path string) (int64, error) {
|
|
file, err := s.client.GetObject(context.Background(), &s3.GetObjectInput{
|
|
Bucket: aws.String(s.bucket),
|
|
Key: aws.String(path),
|
|
})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer file.Body.Close()
|
|
return aws.ToInt64(file.ContentLength), nil
|
|
}
|
|
|
|
func (s *s3Client) Delete(path string) (bool, error) {
|
|
if _, err := s.client.DeleteObject(context.Background(), &s3.DeleteObjectInput{
|
|
Bucket: aws.String(s.bucket),
|
|
Key: aws.String(path),
|
|
}); err != nil {
|
|
return false, err
|
|
}
|
|
waiter := s3.NewObjectNotExistsWaiter(s.client)
|
|
if err := waiter.Wait(context.Background(), &s3.HeadObjectInput{
|
|
Bucket: aws.String(s.bucket),
|
|
Key: aws.String(path),
|
|
}, 30*time.Second); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *s3Client) Upload(src, target string) (bool, error) {
|
|
fileInfo, err := os.Stat(src)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
file, err := os.Open(src)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer file.Close()
|
|
|
|
uploader := manager.NewUploader(s.client)
|
|
maxUploadSize := int64(manager.MaxUploadParts) * manager.DefaultUploadPartSize
|
|
if fileInfo.Size() > maxUploadSize {
|
|
uploader.PartSize = fileInfo.Size() / (int64(manager.MaxUploadParts) - 1)
|
|
}
|
|
if _, err := uploader.Upload(context.Background(), &s3.PutObjectInput{
|
|
Bucket: aws.String(s.bucket),
|
|
Key: aws.String(target),
|
|
Body: file,
|
|
StorageClass: types.StorageClass(s.scType),
|
|
}); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *s3Client) Download(src, target string) (bool, error) {
|
|
if _, err := os.Stat(target); err == nil {
|
|
_ = os.Remove(target)
|
|
}
|
|
file, err := os.Create(target)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer file.Close()
|
|
downloader := manager.NewDownloader(s.client)
|
|
if _, err = downloader.Download(context.Background(), file, &s3.GetObjectInput{
|
|
Bucket: aws.String(s.bucket),
|
|
Key: aws.String(src),
|
|
}); err != nil {
|
|
os.Remove(target)
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *s3Client) ListObjects(prefix string) ([]string, error) {
|
|
var result []string
|
|
outputs, err := s.client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{
|
|
Bucket: aws.String(s.bucket),
|
|
Prefix: aws.String(prefix),
|
|
})
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
for _, item := range outputs.Contents {
|
|
result = append(result, aws.ToString(item.Key))
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func normalizeEndpoint(endpoint string) string {
|
|
if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") {
|
|
return endpoint
|
|
}
|
|
return "http://" + endpoint
|
|
}
|