Yimaru-BackEnd/internal/web_server/handlers/thumbnail_helper.go

86 lines
2.9 KiB
Go

package handlers
import (
"bytes"
"io"
"net/http"
"os"
"path/filepath"
"Yimaru-Backend/internal/domain"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"go.uber.org/zap"
)
func (h *Handler) processAndSaveThumbnail(c *fiber.Ctx, subDir string) (string, error) {
fileHeader, err := c.FormFile("file")
if err != nil {
return "", c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Image file is required", Error: err.Error()})
}
if fileHeader.Size > 10*1024*1024 {
return "", c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "File too large", Error: "Thumbnail image must be <= 10MB"})
}
fh, err := fileHeader.Open()
if err != nil {
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to read file", Error: err.Error()})
}
defer fh.Close()
head := make([]byte, 512)
n, _ := fh.Read(head)
contentType := http.DetectContentType(head[:n])
if contentType != "image/jpeg" && contentType != "image/png" && contentType != "image/webp" {
return "", c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid file type", Error: "Only jpg, png and webp images are allowed"})
}
rest, err := io.ReadAll(fh)
if err != nil {
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to read file", Error: err.Error()})
}
data := append(head[:n], rest...)
if h.cloudConvertSvc != nil {
optimized, optErr := h.cloudConvertSvc.OptimizeImage(c.Context(), fileHeader.Filename, bytes.NewReader(data), int64(len(data)), 1200, 80)
if optErr != nil {
h.mongoLoggerSvc.Warn("CloudConvert thumbnail optimization failed, using original", zap.Error(optErr))
} else {
optimizedData, readErr := io.ReadAll(optimized.Data)
optimized.Data.Close()
if readErr == nil {
data = optimizedData
contentType = "image/webp"
}
}
}
if h.minioSvc != nil {
result, uploadErr := h.minioSvc.Upload(c.Context(), subDir, fileHeader.Filename, bytes.NewReader(data), int64(len(data)), contentType)
if uploadErr != nil {
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to upload file to storage", Error: uploadErr.Error()})
}
return "minio://" + result.ObjectKey, nil
}
ext := ".jpg"
if contentType == "image/png" {
ext = ".png"
}
if contentType == "image/webp" {
ext = ".webp"
}
dir := filepath.Join(".", "static", subDir)
if err := os.MkdirAll(dir, 0o755); err != nil {
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to create storage directory", Error: err.Error()})
}
filename := uuid.New().String() + ext
fullpath := filepath.Join(dir, filename)
if err := os.WriteFile(fullpath, data, 0o644); err != nil {
return "", c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to save file", Error: err.Error()})
}
return "/static/" + subDir + "/" + filename, nil
}