Files
healthflow/server/internal/handler/upload.go
2026-01-02 17:35:32 +08:00

115 lines
2.8 KiB
Go

package handler
import (
"context"
"fmt"
"io"
"net/http"
"path/filepath"
"strings"
"time"
"healthflow/internal/config"
"github.com/aws/aws-sdk-go-v2/aws"
awsconfig "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type UploadHandler struct {
cfg *config.Config
s3Client *s3.Client
}
func NewUploadHandler(cfg *config.Config) *UploadHandler {
h := &UploadHandler{cfg: cfg}
// 初始化 R2 客户端
if cfg.R2AccountID != "" && cfg.R2AccessKeyID != "" {
r2Resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{
URL: fmt.Sprintf("https://%s.r2.cloudflarestorage.com", cfg.R2AccountID),
}, nil
})
awsCfg, err := awsconfig.LoadDefaultConfig(context.TODO(),
awsconfig.WithEndpointResolverWithOptions(r2Resolver),
awsconfig.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
cfg.R2AccessKeyID,
cfg.R2AccessKeySecret,
"",
)),
awsconfig.WithRegion("auto"),
)
if err == nil {
h.s3Client = s3.NewFromConfig(awsCfg)
}
}
return h
}
func (h *UploadHandler) Upload(c *gin.Context) {
file, header, err := c.Request.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "no file uploaded"})
return
}
defer file.Close()
// 生成唯一文件名
ext := filepath.Ext(header.Filename)
filename := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), uuid.New().String()[:8], ext)
// 上传到 R2
if h.s3Client != nil {
key := "memory/healthFlow/pic/" + filename
_, err := h.s3Client.PutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(h.cfg.R2BucketName),
Key: aws.String(key),
Body: file,
ContentType: aws.String(header.Header.Get("Content-Type")),
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to upload to R2"})
return
}
url := fmt.Sprintf("%s/%s", h.cfg.R2PublicURL, key)
c.JSON(http.StatusOK, gin.H{"url": url})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "no storage configured"})
}
func (h *UploadHandler) GetFile(c *gin.Context) {
filepath := c.Param("filepath")
filepath = strings.TrimPrefix(filepath, "/")
if h.s3Client == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "file not found"})
return
}
result, err := h.s3Client.GetObject(context.TODO(), &s3.GetObjectInput{
Bucket: aws.String(h.cfg.R2BucketName),
Key: aws.String(filepath),
})
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "file not found"})
return
}
defer result.Body.Close()
if result.ContentType != nil {
c.Header("Content-Type", *result.ContentType)
}
io.Copy(c.Writer, result.Body)
}