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", "", )), awsConfig.WithEndpointResolver(aws.EndpointResolverFunc( func(service, region string) (aws.Endpoint, error) { return aws.Endpoint{ URL: "https://s3.regru.cloud", SigningRegion: "ru-central1", Source: aws.EndpointSourceCustom, }, nil }, )), ) if err != nil { return nil, err } // Создаем клиент с кастомным эндпоинтом client := s3.NewFromConfig(cfg, func(o *s3.Options) { o.UsePathStyle = true // Важно для некоторых S3 провайдеров }) 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), }, 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 }