package S3 import ( "context" "fmt" "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" awsConfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/s3" ) // Получаем S3 клиент func getS3Client() (*s3.Client, error) { cfg, err := awsConfig.LoadDefaultConfig(context.TODO(), awsConfig.WithRegion("ru-central1"), awsConfig.WithCredentialsProvider(credentials.NewStaticCredentialsProvider( "TJ946G2S1Z5FEI3I7DQQ", "C2H2aITHRDpek8H921yhnrINZwDoADsjW3F6HURl", "", )), ) if err != nil { return nil, err } // Используем virtual-hosted-style endpoint client := s3.NewFromConfig(cfg, func(o *s3.Options) { o.BaseEndpoint = aws.String("https://tailly.website.regru.cloud") o.UsePathStyle = false // Отключаем path-style }) return client, nil } func DeleteFromS3(imageURL string) error { const op = "s3.DeleteFromS3" parts := strings.SplitN(strings.TrimPrefix(imageURL, "https://s3.regru.cloud/"), "/", 2) if len(parts) != 2 { return fmt.Errorf("%s: invalid S3 URL format", op) } bucket := parts[0] key := parts[1] client, err := getS3Client() if err != nil { return fmt.Errorf("%s: failed to create S3 client: %w", op, err) } _, err = client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), }) if err != nil { return fmt.Errorf("%s: failed to delete object from S3: %w", op, err) } // Ждем пока объект исчезнет waiter := s3.NewObjectNotExistsWaiter(client) err = waiter.Wait(context.TODO(), &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), }, 30*time.Second) if err != nil { return fmt.Errorf("%s: failed to wait for object deletion: %w", op, err) } return nil } func GeneratePresignedUploadURL(userID int, filename string) (string, string, error) { const op = "s3.GeneratePresignedUploadURL" client, err := getS3Client() if err != nil { return "", "", fmt.Errorf("%s: failed to create S3 client: %w", op, err) } uniqueKey := fmt.Sprintf("posts/%d/%d_%s", userID, time.Now().UnixNano(), filename) presignClient := s3.NewPresignClient(client) result, err := presignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String("tailly"), Key: aws.String(uniqueKey), ContentLength: aws.Int64(10 * 1024 * 1024), // Добавляем CORS headers через метаданные Metadata: map[string]string{ "Access-Control-Allow-Origin": "https://tailly.ru", "Access-Control-Allow-Methods": "PUT, POST, DELETE", "Access-Control-Allow-Headers": "*", }, }, s3.WithPresignExpires(15*time.Minute), ) if err != nil { return "", "", fmt.Errorf("%s: failed to generate presigned URL: %w", op, err) } return result.URL, uniqueKey, nil }