package upload import ( "bytes" "clapclap/internal/apperr" "clapclap/internal/dtos" "clapclap/internal/env" "clapclap/internal/ginctx" "context" "fmt" "io" "log" "net/url" "strings" "clapclap/internal/uuid" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/gin-gonic/gin" ) func GenerateObjectKey(c *gin.Context) { req, err := ginctx.GetDto[dtos.UploadFile](c) if err != nil { apperr.AbortWithError(c, apperr.NewValidationError(err)) return } var prefix string = "" var isPublic bool = req.IsPublic switch c.Param("type") { case "track": prefix = "tracks" if isPublic { prefix += "/public/audios" } else { prefix += "/private/audios" } case "artwork": prefix = "tracks" if isPublic { prefix += "/public/artworks" } else { prefix += "/private/artworks" } case "avatar": prefix = "avatars" } objectKey := fmt.Sprintf( "%s/%s-%s", prefix, uuid.New().String(), req.Filename, ) c.Set("s3ObjectKey", objectKey) } func DownloadObjFromS3(c *gin.Context, bucket string, objKey string) []byte { s3ic, err := ginctx.GetS3(c, "s3-internal") if err != nil { return nil } ctx := c.Request.Context() downloadedObj, err := s3ic.GetObject(ctx, &s3.GetObjectInput{ Bucket: aws.String(bucket), Key: aws.String(objKey), }) if err != nil { return nil } bytesToRead := env.C.FILETYPE_CHECK_NB_BYTES_TO_READ chunk := make([]byte, bytesToRead) _, err = io.ReadFull(downloadedObj.Body, chunk) if err != nil && err != io.EOF { return nil } downloadedObj.Body.Close() return chunk } func DeleteS3Object(ctx context.Context, s3Client *s3.Client, bucket, key string) error { _, err := s3Client.DeleteObject(ctx, &s3.DeleteObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), }) if err != nil { log.Printf("Failed to delete object %s from bucket %s: %v", key, bucket, err) return err } log.Printf("Successfully deleted object %s from bucket %s", key, bucket) return nil } func IsObjectImg(objectKey string) bool { return strings.HasPrefix(objectKey, "tracks/public/artworks/") || strings.HasPrefix(objectKey, "tracks/private/artworks/") || strings.HasPrefix(objectKey, "avatars/") || strings.HasPrefix(objectKey, "avatars_generated/") } func IsObjectTrack(objectKey string) bool { return strings.HasPrefix(objectKey, "tracks/public/audios/") || strings.HasPrefix(objectKey, "tracks/private/audios/") } func UploadBufferToS3(ctx context.Context, s3Client *s3.Client, bucket, key string, buf *bytes.Buffer, contentType string) error { _, err := s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: aws.String(bucket), Key: aws.String(key), Body: bytes.NewReader(buf.Bytes()), ContentType: aws.String(contentType), }) return err } func GetObjectKeyFromUrl(s string) (string, error) { u, err := url.Parse(s) if err != nil { return "", err } // Get path without leading slash key := strings.TrimPrefix(u.Path, "/") // Nginx reverse proxy adds "clap/" before the bucket. We must strip both. proxyPrefix := "clap/" + env.C.BUCKET_NAME if strings.HasPrefix(key, proxyPrefix+"/") { key = strings.TrimPrefix(key, proxyPrefix+"/") } else if strings.HasPrefix(key, env.C.BUCKET_NAME+"/") { key = strings.TrimPrefix(key, env.C.BUCKET_NAME+"/") } return key, nil }