Files
EchoChat/backend/go-service/app/file/controller/file_controller.go

157 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package controller 提供文件上传模块的 HTTP 接口处理
package controller
import (
"strconv"
"github.com/echochat/backend/app/file/service"
"github.com/echochat/backend/pkg/middleware"
"github.com/echochat/backend/pkg/utils"
"github.com/gin-gonic/gin"
)
const (
maxUploadSize = 50 << 20 // 50 MB通用上传
maxImageUploadSize = 20 << 20 // 20 MB图片上传
maxVoiceUploadSize = 5 << 20 // 5 MB语音上传
)
// FileController 文件上传控制器
type FileController struct {
fileService *service.FileService
}
// NewFileController 创建文件上传控制器
func NewFileController(fileService *service.FileService) *FileController {
return &FileController{fileService: fileService}
}
// Upload 处理通用文件上传请求
// POST /api/v1/upload
// 支持 multipart/form-data字段名为 "file",最大 50MB
func (ctl *FileController) Upload(c *gin.Context) {
ctx := c.Request.Context()
_, ok := middleware.GetCurrentUserID(c)
if !ok {
utils.ResponseUnauthorized(c, "无法获取当前用户信息")
return
}
fileHeader, err := c.FormFile("file")
if err != nil {
utils.ResponseBadRequest(c, "请选择要上传的文件")
return
}
if fileHeader.Size > maxUploadSize {
utils.ResponseBadRequest(c, "文件大小不能超过 50MB")
return
}
result, err := ctl.fileService.Upload(ctx, fileHeader)
if err != nil {
ctl.handleError(c, err, "文件上传失败")
return
}
utils.ResponseOK(c, result)
}
// UploadImage 处理图片上传请求,自动生成缩略图
// POST /api/v1/upload/image
// 支持 multipart/form-data字段名为 "file",最大 20MB
// 返回原图 URL + 缩略图 URL + 宽高信息
func (ctl *FileController) UploadImage(c *gin.Context) {
ctx := c.Request.Context()
_, ok := middleware.GetCurrentUserID(c)
if !ok {
utils.ResponseUnauthorized(c, "无法获取当前用户信息")
return
}
fileHeader, err := c.FormFile("file")
if err != nil {
utils.ResponseBadRequest(c, "请选择要上传的图片")
return
}
if fileHeader.Size > maxImageUploadSize {
utils.ResponseBadRequest(c, "图片大小不能超过 20MB")
return
}
result, err := ctl.fileService.UploadImage(ctx, fileHeader)
if err != nil {
ctl.handleError(c, err, "图片上传失败")
return
}
utils.ResponseOK(c, result)
}
// UploadVoice 处理语音上传请求,校验格式和时长
// POST /api/v1/upload/voice
// 支持 multipart/form-data字段名为 "file",另需 "duration" 字段(秒)
// 最大 5MB时长不超过 60 秒
func (ctl *FileController) UploadVoice(c *gin.Context) {
ctx := c.Request.Context()
_, ok := middleware.GetCurrentUserID(c)
if !ok {
utils.ResponseUnauthorized(c, "无法获取当前用户信息")
return
}
fileHeader, err := c.FormFile("file")
if err != nil {
utils.ResponseBadRequest(c, "请选择要上传的语音文件")
return
}
if fileHeader.Size > maxVoiceUploadSize {
utils.ResponseBadRequest(c, "语音文件大小不能超过 5MB")
return
}
durationStr := c.PostForm("duration")
duration := 0
if durationStr != "" {
duration, err = strconv.Atoi(durationStr)
if err != nil || duration < 0 {
utils.ResponseBadRequest(c, "语音时长参数无效")
return
}
}
result, err := ctl.fileService.UploadVoice(ctx, fileHeader, duration)
if err != nil {
ctl.handleError(c, err, "语音上传失败")
return
}
utils.ResponseOK(c, result)
}
// handleError 统一业务错误映射
func (ctl *FileController) handleError(c *gin.Context, err error, fallbackMsg ...string) {
switch err {
case service.ErrFileOpen:
utils.ResponseBadRequest(c, err.Error())
case service.ErrInvalidImage:
utils.ResponseBadRequest(c, err.Error())
case service.ErrInvalidVoice:
utils.ResponseBadRequest(c, err.Error())
case service.ErrVoiceTooLong:
utils.ResponseBadRequest(c, err.Error())
case service.ErrFileTooLarge:
utils.ResponseBadRequest(c, err.Error())
case service.ErrUploadFailed, service.ErrThumbnailGen:
utils.ResponseError(c, err.Error())
default:
msg := "服务器内部错误"
if len(fallbackMsg) > 0 && fallbackMsg[0] != "" {
msg = fallbackMsg[0]
}
utils.ResponseError(c, msg)
}
}