172 lines
5.1 KiB
Go
172 lines
5.1 KiB
Go
package imageuploader
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"likedream-goframe/internal/application/cpdaily/types"
|
|
"likedream-goframe/internal/application/filestorage"
|
|
"likedream-goframe/internal/common/db"
|
|
"likedream-goframe/internal/common/errors"
|
|
"likedream-goframe/internal/ent"
|
|
"likedream-goframe/internal/ent/cpimage"
|
|
"likedream-goframe/internal/utils"
|
|
|
|
"github.com/bytedance/sonic"
|
|
"github.com/google/uuid"
|
|
"github.com/samber/oops"
|
|
"resty.dev/v3"
|
|
)
|
|
|
|
// CpImageUploadPolicy 结构体用于表示图片上传策略的相关信息
|
|
type CpImageUploadPolicy struct {
|
|
AccessId string `json:"accessid"`
|
|
FileName string `json:"fileName"`
|
|
Policy string `json:"policy"`
|
|
Host string `json:"host"`
|
|
Signature string `json:"signature"`
|
|
}
|
|
|
|
func UploadImageFromStorage(ctx context.Context, host string, imageId uuid.UUID, taskType types.TaskType, client *resty.Client) string {
|
|
targetImage, e := db.Global.CpImage.Query().
|
|
Where(cpimage.ImageID(imageId)).
|
|
Select(cpimage.FieldKey, cpimage.FieldContentType).
|
|
Only(ctx)
|
|
|
|
if e != nil {
|
|
if ent.IsNotFound(e) {
|
|
utils.OkOrPanic(errors.NewBusinessError(503, "图片不存在"), oops.WithContext(ctx).Wrap)
|
|
}
|
|
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
|
}
|
|
|
|
imageUploadPolicy := GetUploadPolicyAsync(ctx, host, taskType, client)
|
|
|
|
targetFile := filestorage.GlobalS3.GetFile(ctx, targetImage.Key)
|
|
|
|
resp, e := client.R().
|
|
SetMultipartFields(&resty.MultipartField{
|
|
Name: "x-obs-acl",
|
|
Values: []string{"public-read"},
|
|
}, &resty.MultipartField{
|
|
Name: "AccessKeyId",
|
|
Values: []string{imageUploadPolicy.AccessId},
|
|
}, &resty.MultipartField{
|
|
Name: "key",
|
|
Values: []string{imageUploadPolicy.FileName},
|
|
}, &resty.MultipartField{
|
|
Name: "signature",
|
|
Values: []string{imageUploadPolicy.Signature},
|
|
}, &resty.MultipartField{
|
|
Name: "policy",
|
|
Values: []string{imageUploadPolicy.Policy},
|
|
}, &resty.MultipartField{
|
|
Name: "content-type",
|
|
Values: []string{targetImage.ContentType},
|
|
}, &resty.MultipartField{
|
|
Name: "file",
|
|
FileName: "file",
|
|
Reader: targetFile,
|
|
}).
|
|
Post(imageUploadPolicy.Host)
|
|
|
|
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
|
|
|
if resp.StatusCode() > 299 {
|
|
utils.OkOrPanic(errors.NewBusinessError(503, "上传图片失败: "+utils.ReadString(resp.Body)), oops.WithContext(ctx).With("response", utils.ReadString(resp.Body)).Wrap)
|
|
}
|
|
|
|
previewUrl := GetPreviewUrlAsync(ctx, host, imageUploadPolicy.FileName, taskType, client)
|
|
|
|
return previewUrl
|
|
}
|
|
|
|
// GetPreviewUrlAsync 用于获取图片预览地址
|
|
func GetPreviewUrlAsync(ctx context.Context, host string, fileKey string, taskType types.TaskType, client *resty.Client) string {
|
|
var apiPath string
|
|
if taskType == types.TaskTypeSleepCheck {
|
|
apiPath = "/previewAttachment"
|
|
} else {
|
|
apiPath = "/sign/previewAttachment"
|
|
}
|
|
urlPrefix := GetImageUploadUrlPrefix(ctx, taskType)
|
|
fullUrl := host + urlPrefix + apiPath
|
|
|
|
reqBody := map[string]interface{}{
|
|
"ossKey": fileKey,
|
|
}
|
|
|
|
resp, err := client.R().
|
|
SetBody(reqBody).
|
|
Post(fullUrl)
|
|
utils.OkOrPanic(err, oops.WithContext(ctx).Wrap)
|
|
defer resp.Body.Close()
|
|
|
|
responseJSON := utils.ReadJson[map[string]*json.RawMessage](resp.Body)
|
|
datas := responseJSON["datas"]
|
|
|
|
if datas == nil {
|
|
utils.OkOrPanic(errors.NewBusinessError(404, "上传图片URL为空"), oops.WithContext(ctx).With("response", responseJSON).Wrap)
|
|
}
|
|
|
|
var previewUrl string
|
|
utils.OkOrPanic(sonic.Unmarshal(*datas, &previewUrl), oops.WithContext(ctx).Wrap)
|
|
return previewUrl
|
|
}
|
|
|
|
// GetUploadPolicyAsync 用于获取图片上传策略
|
|
func GetUploadPolicyAsync(ctx context.Context, host string, taskType types.TaskType, client *resty.Client) *CpImageUploadPolicy {
|
|
// 构造请求路径
|
|
urlPrefix := GetImageUploadUrlPrefix(ctx, taskType)
|
|
var apiPath string
|
|
if taskType == types.TaskTypeSleepCheck {
|
|
apiPath = "/getUploadPolicy"
|
|
} else {
|
|
apiPath = "/obs/getUploadPolicy"
|
|
}
|
|
fullUrl := host + urlPrefix + apiPath
|
|
|
|
// 构造请求体
|
|
reqBody := map[string]interface{}{
|
|
"fileType": 1,
|
|
}
|
|
|
|
// 构造请求
|
|
req := client.R().SetBody(reqBody)
|
|
|
|
// 发送请求
|
|
resp, err := req.Post(fullUrl)
|
|
if err != nil {
|
|
utils.OkOrPanic(err, oops.WithContext(ctx).Wrap)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
responseJSON := utils.ReadJson[map[string]*json.RawMessage](resp.Body)
|
|
|
|
datas := responseJSON["datas"]
|
|
|
|
if datas == nil {
|
|
utils.OkOrPanic(errors.NewBusinessError(503, "获取图片上传策略失败: 响应中缺少 datas 字段"), oops.WithContext(ctx).With("response", responseJSON).Wrap)
|
|
}
|
|
|
|
var policy CpImageUploadPolicy
|
|
|
|
utils.OkOrPanic(sonic.Unmarshal(*datas, &policy), oops.WithContext(ctx).Wrap)
|
|
|
|
return &policy
|
|
}
|
|
|
|
// GetImageUploadUrlPrefix 根据任务类型返回图片上传的URL前缀
|
|
func GetImageUploadUrlPrefix(ctx context.Context, taskType types.TaskType) string {
|
|
switch taskType {
|
|
case types.TaskTypeSleepCheck:
|
|
return "/wec-counselor-attendance-apps/student/attendance"
|
|
case types.TaskTypeSign:
|
|
return "/wec-counselor-sign-apps/stu"
|
|
case types.TaskTypeCollection:
|
|
return "/wec-counselor-collector-apps/student/collector"
|
|
default:
|
|
utils.OkOrPanic(errors.NewBusinessError(503, "未知的任务类型"), oops.WithContext(ctx).Wrap)
|
|
panic("unreachable")
|
|
}
|
|
}
|