Files
X-Agents/server/internal/handler/upload_handler.go

134 lines
3.6 KiB
Go
Raw Normal View History

package handler
import (
"io"
"mime"
"net/http"
"path/filepath"
"github.com/gin-gonic/gin"
"x-agents/server/internal/repository"
"x-agents/server/internal/service"
)
type UploadHandler struct {
uploadService *service.UploadService
knowledgeRepo *repository.KnowledgeRepository
}
func NewUploadHandler(uploadService *service.UploadService, knowledgeRepo *repository.KnowledgeRepository) *UploadHandler {
return &UploadHandler{uploadService: uploadService, knowledgeRepo: knowledgeRepo}
}
// Upload 上传文件
func (h *UploadHandler) Upload(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "No file uploaded"})
return
}
// 检查文件大小(最大 100MB
if file.Size > 100*1024*1024 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "File too large (max 100MB)"})
return
}
result, err := h.uploadService.Upload(file)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
if !result.Success {
c.JSON(http.StatusInternalServerError, result)
return
}
c.JSON(http.StatusOK, result)
}
// Delete 删除文件
func (h *UploadHandler) Delete(c *gin.Context) {
filename := c.Param("filename")
if filename == "" {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "Filename is required"})
return
}
if err := h.uploadService.DeleteFile(filename); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "File deleted"})
}
// ProxyFile 代理文件访问(解决 MinIO 内网地址和 HTTPS 问题)
func (h *UploadHandler) ProxyFile(c *gin.Context) {
fileKey := c.Query("key")
kbID := c.Query("kb_id")
if fileKey == "" {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "File key is required"})
return
}
var content io.Reader
var contentType string
// 如果提供了知识库 ID使用知识库的存储配置
if kbID != "" && h.knowledgeRepo != nil {
kb, err := h.knowledgeRepo.FindByID(kbID)
if err == nil && kb.StorageConfig.Type == "minio" {
reader, ct, err := h.uploadService.GetFileContentWithConfig(fileKey, kb.StorageConfig)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
content = reader
contentType = ct
defer reader.Close()
} else {
// 使用全局配置
reader, ct, err := h.uploadService.GetFileContent(fileKey)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
content = reader
contentType = ct
defer reader.Close()
}
} else {
// 使用全局配置
reader, ct, err := h.uploadService.GetFileContent(fileKey)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
content = reader
contentType = ct
defer reader.Close()
}
// 设置响应头
// 如果 Content-Type 是 application/octet-stream根据文件扩展名推断
if contentType == "application/octet-stream" {
ext := filepath.Ext(fileKey)
if detected := mime.TypeByExtension(ext); detected != "" {
contentType = detected
}
}
if contentType != "" {
c.Header("Content-Type", contentType)
} else {
c.Header("Content-Type", "application/octet-stream")
}
c.Header("Content-Disposition", "inline")
// 直接流式输出文件内容
c.DataFromReader(http.StatusOK, -1, contentType, content, nil)
}