94 lines
2.5 KiB
Go
94 lines
2.5 KiB
Go
|
|
package upload
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"encoding/base64"
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"qnc-server/app/main/api/internal/svc"
|
||
|
|
"qnc-server/app/main/api/internal/types"
|
||
|
|
"qnc-server/common/xerr"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"github.com/pkg/errors"
|
||
|
|
"github.com/zeromicro/go-zero/core/logx"
|
||
|
|
)
|
||
|
|
|
||
|
|
const uploadImageDir = "uploads/images"
|
||
|
|
|
||
|
|
type UploadImageLogic struct {
|
||
|
|
logx.Logger
|
||
|
|
ctx context.Context
|
||
|
|
svcCtx *svc.ServiceContext
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewUploadImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadImageLogic {
|
||
|
|
return &UploadImageLogic{
|
||
|
|
Logger: logx.WithContext(ctx),
|
||
|
|
ctx: ctx,
|
||
|
|
svcCtx: svcCtx,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (l *UploadImageLogic) UploadImage(req *types.UploadImageReq) (*types.UploadImageResp, error) {
|
||
|
|
raw := strings.TrimSpace(req.ImageBase64)
|
||
|
|
if raw == "" {
|
||
|
|
return nil, errors.Wrapf(xerr.NewErrMsg("image_base64 不能为空"), "")
|
||
|
|
}
|
||
|
|
if idx := strings.Index(raw, ","); idx >= 0 {
|
||
|
|
raw = raw[idx+1:]
|
||
|
|
}
|
||
|
|
data, err := base64.StdEncoding.DecodeString(raw)
|
||
|
|
if err != nil {
|
||
|
|
return nil, errors.Wrapf(xerr.NewErrMsg("图片 Base64 解析失败"), "")
|
||
|
|
}
|
||
|
|
if len(data) == 0 {
|
||
|
|
return nil, errors.Wrapf(xerr.NewErrMsg("图片内容为空"), "")
|
||
|
|
}
|
||
|
|
if len(data) > 5*1024*1024 {
|
||
|
|
return nil, errors.Wrapf(xerr.NewErrMsg("图片不能超过 5MB"), "")
|
||
|
|
}
|
||
|
|
|
||
|
|
ext := detectImageExt(data)
|
||
|
|
fileName := fmt.Sprintf("%s%s", uuid.NewString(), ext)
|
||
|
|
dir := uploadImageDir
|
||
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||
|
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建上传目录失败: %v", err)
|
||
|
|
}
|
||
|
|
fullPath := filepath.Join(dir, fileName)
|
||
|
|
if err := os.WriteFile(fullPath, data, 0o644); err != nil {
|
||
|
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "保存图片失败: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
base := publicAPIBase(l.svcCtx.Config.Promotion.OfficialDomain)
|
||
|
|
url := fmt.Sprintf("%s/api/v1/upload/file/%s", base, fileName)
|
||
|
|
return &types.UploadImageResp{Url: url}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func detectImageExt(data []byte) string {
|
||
|
|
if len(data) >= 3 && data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF {
|
||
|
|
return ".jpg"
|
||
|
|
}
|
||
|
|
if len(data) >= 8 && string(data[0:8]) == "\x89PNG\r\n\x1a\n" {
|
||
|
|
return ".png"
|
||
|
|
}
|
||
|
|
if len(data) >= 6 && string(data[0:6]) == "GIF87a" || string(data[0:6]) == "GIF89a" {
|
||
|
|
return ".gif"
|
||
|
|
}
|
||
|
|
if len(data) >= 12 && string(data[8:12]) == "WEBP" {
|
||
|
|
return ".webp"
|
||
|
|
}
|
||
|
|
return ".jpg"
|
||
|
|
}
|
||
|
|
|
||
|
|
func publicAPIBase(officialDomain string) string {
|
||
|
|
base := strings.TrimRight(officialDomain, "/")
|
||
|
|
if base != "" {
|
||
|
|
return base
|
||
|
|
}
|
||
|
|
return "http://127.0.0.1:8888"
|
||
|
|
}
|