mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-21 00:24:12 +08:00
* fix: apply timeout to snapshot uploads * fix: honor snapshot upload timeouts for sftp and upyun
186 lines
4.4 KiB
Go
186 lines
4.4 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
)
|
|
|
|
const (
|
|
s3DefaultTimeout = 30 * time.Second
|
|
s3TransferTimeout = 24 * time.Hour
|
|
)
|
|
|
|
type s3Client struct {
|
|
scType string
|
|
bucket string
|
|
client *minio.Client
|
|
}
|
|
|
|
func (s *s3Client) ctx(timeout time.Duration) (context.Context, context.CancelFunc) {
|
|
return context.WithTimeout(context.Background(), timeout)
|
|
}
|
|
|
|
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"
|
|
}
|
|
|
|
lookupStyle := minio.BucketLookupDNS
|
|
if mode == "path" {
|
|
lookupStyle = minio.BucketLookupPath
|
|
}
|
|
|
|
ssl := strings.Split(endpoint, ":")[0]
|
|
secure := false
|
|
tlsConfig := &tls.Config{}
|
|
if ssl == "https" {
|
|
secure = true
|
|
tlsConfig.InsecureSkipVerify = true
|
|
}
|
|
var transport http.RoundTripper = &http.Transport{
|
|
TLSClientConfig: tlsConfig,
|
|
}
|
|
|
|
endpoint = strings.TrimPrefix(endpoint, ssl+"://")
|
|
|
|
client, err := minio.New(endpoint, &minio.Options{
|
|
Creds: credentials.NewStaticV4(accessKey, secretKey, ""),
|
|
Secure: secure,
|
|
Region: region,
|
|
BucketLookup: lookupStyle,
|
|
Transport: transport,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &s3Client{scType: scType, bucket: bucket, client: client}, nil
|
|
}
|
|
|
|
func (s s3Client) ListBuckets() ([]interface{}, error) {
|
|
ctx, cancel := s.ctx(s3DefaultTimeout)
|
|
defer cancel()
|
|
buckets, err := s.client.ListBuckets(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var result []interface{}
|
|
for _, b := range buckets {
|
|
result = append(result, b.Name)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (s s3Client) Exist(path string) (bool, error) {
|
|
ctx, cancel := s.ctx(s3DefaultTimeout)
|
|
defer cancel()
|
|
_, err := s.client.StatObject(ctx, s.bucket, path, minio.StatObjectOptions{})
|
|
if err != nil {
|
|
resp := minio.ToErrorResponse(err)
|
|
if resp.StatusCode == 404 {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *s3Client) Size(path string) (int64, error) {
|
|
ctx, cancel := s.ctx(s3DefaultTimeout)
|
|
defer cancel()
|
|
info, err := s.client.StatObject(ctx, s.bucket, path, minio.StatObjectOptions{})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return info.Size, nil
|
|
}
|
|
|
|
func (s s3Client) Delete(path string) (bool, error) {
|
|
ctx, cancel := s.ctx(s3DefaultTimeout)
|
|
defer cancel()
|
|
if err := s.client.RemoveObject(ctx, s.bucket, path, minio.RemoveObjectOptions{}); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s s3Client) Upload(ctx context.Context, 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()
|
|
|
|
opts := minio.PutObjectOptions{
|
|
StorageClass: s.scType,
|
|
}
|
|
|
|
const maxParts = 10000
|
|
const defaultPartSize = 64 * 1024 * 1024 // 64 MiB
|
|
partSize := uint64(defaultPartSize)
|
|
if fileInfo.Size() > int64(maxParts)*int64(defaultPartSize) {
|
|
partSize = uint64(fileInfo.Size()) / (maxParts - 1)
|
|
}
|
|
opts.PartSize = partSize
|
|
|
|
if _, ok := ctx.Deadline(); !ok {
|
|
var cancel context.CancelFunc
|
|
ctx, cancel = s.ctx(s3TransferTimeout)
|
|
defer cancel()
|
|
}
|
|
if _, err := s.client.PutObject(ctx, s.bucket, target, file, fileInfo.Size(), opts); 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)
|
|
}
|
|
ctx, cancel := s.ctx(s3TransferTimeout)
|
|
defer cancel()
|
|
if err := s.client.FGetObject(ctx, s.bucket, src, target, minio.GetObjectOptions{}); err != nil {
|
|
os.Remove(target)
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *s3Client) ListObjects(prefix string) ([]string, error) {
|
|
opts := minio.ListObjectsOptions{
|
|
Recursive: true,
|
|
Prefix: prefix,
|
|
}
|
|
var result []string
|
|
ctx, cancel := s.ctx(s3DefaultTimeout)
|
|
defer cancel()
|
|
for object := range s.client.ListObjects(ctx, s.bucket, opts) {
|
|
if object.Err != nil {
|
|
return result, object.Err
|
|
}
|
|
result = append(result, object.Key)
|
|
}
|
|
return result, nil
|
|
}
|