feat: add file upload workflow
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"hfb_sys/backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
service *Service
|
||||
storage *Storage
|
||||
}
|
||||
|
||||
func NewHandler(service *Service, storage *Storage) *Handler {
|
||||
return &Handler{service: service, storage: storage}
|
||||
}
|
||||
|
||||
func (h *Handler) Upload(c *gin.Context) {
|
||||
header, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
response.BadRequest(c, "请选择要上传的文件")
|
||||
return
|
||||
}
|
||||
reader, err := header.Open()
|
||||
if err != nil {
|
||||
response.BadRequest(c, "文件读取失败")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = reader.Close()
|
||||
}()
|
||||
item, err := h.service.Upload(uploadRequest{
|
||||
Context: c.Request.Context(),
|
||||
Scene: c.PostForm("scene"),
|
||||
Header: header,
|
||||
Reader: reader,
|
||||
ContentType: header.Header.Get("Content-Type"),
|
||||
})
|
||||
if err != nil {
|
||||
writeFileError(c, err)
|
||||
return
|
||||
}
|
||||
response.Created(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) Object(c *gin.Context) {
|
||||
if h.storage == nil {
|
||||
response.ServiceUnavailable(c, "文件存储未连接")
|
||||
return
|
||||
}
|
||||
key := strings.TrimSpace(c.Query("key"))
|
||||
if key == "" || strings.Contains(key, "..") {
|
||||
response.BadRequest(c, "文件 key 不正确")
|
||||
return
|
||||
}
|
||||
object, err := h.storage.Get(c.Request.Context(), key)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusNotFound, "not_found", "文件不存在或暂不可访问")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = object.Reader.Close()
|
||||
}()
|
||||
contentType := object.ContentType
|
||||
if contentType == "" {
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
c.Header("Content-Type", contentType)
|
||||
c.Header("Cache-Control", "private, max-age=300")
|
||||
c.DataFromReader(http.StatusOK, object.Size, contentType, object.Reader, nil)
|
||||
}
|
||||
|
||||
func writeFileError(c *gin.Context, err error) {
|
||||
switch {
|
||||
case errors.Is(err, ErrDependencyUnavailable):
|
||||
response.ServiceUnavailable(c, "文件存储未连接")
|
||||
case errors.Is(err, ErrInvalidFile):
|
||||
response.BadRequest(c, "文件不符合规则,仅支持 10MB 内的 JPG、PNG、WebP 或 PDF")
|
||||
default:
|
||||
response.Error(c, http.StatusInternalServerError, "internal_error", "文件服务暂时不可用")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user