♻️ refactored thumbnail storage strategy

This commit is contained in:
2025-02-28 01:42:44 +08:00
parent 693ed8755c
commit 58c58546d2
32 changed files with 405 additions and 425 deletions

View File

@@ -11,8 +11,7 @@ import (
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"sync"
"time"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
@@ -27,6 +26,16 @@ type QueryShareImageLogic struct {
svcCtx *svc.ServiceContext
}
var WeekdayMap = map[time.Weekday]string{
time.Sunday: "日",
time.Monday: "一",
time.Tuesday: "二",
time.Wednesday: "三",
time.Thursday: "四",
time.Friday: "五",
time.Saturday: "六",
}
func NewQueryShareImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryShareImageLogic {
return &QueryShareImageLogic{
Logger: logx.WithContext(ctx),
@@ -139,24 +148,11 @@ func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.Sca
if err != nil {
return nil, err
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + storageShare.UserID + ":" + storageShare.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, storageShare.UserID, storageShare.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(storageShare.UserID, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
reqParams := make(url.Values)
// 使用 errgroup 和 semaphore 并发处理图片信息
var ResultList []types.ShareImageListMeta
g, ctx := errgroup.WithContext(l.ctx)
sem := semaphore.NewWeighted(10) // 限制并发数为 10
groupedImages := sync.Map{}
for _, imgInfo := range storageInfoList {
imgInfo := imgInfo // 创建局部变量,避免闭包问题
if err := sem.Acquire(ctx, 1); err != nil {
@@ -164,25 +160,32 @@ func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.Sca
}
g.Go(func() error {
defer sem.Release(1)
ossURL, err := service.PresignedURL(ctx, ossConfig.BucketName, imgInfo.Path, 30*time.Minute)
// 生成日期分类键
weekday := WeekdayMap[imgInfo.CreatedAt.Weekday()]
date := imgInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
ossUrl, err := l.svcCtx.MinioClient.PresignedGetObject(ctx, constant.ShareImagesBucketName, imgInfo.Path, 30*time.Minute, reqParams)
if err != nil {
return errors.New("get presigned url failed")
}
reqParams := make(url.Values)
presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(ctx, constant.ThumbnailBucketName, imgInfo.ThumbPath, 30*time.Minute, reqParams)
if err != nil {
return errors.New("get presigned thumbnail url failed")
}
ResultList = append(ResultList, types.ShareImageListMeta{
// 原子操作更新分组数据
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
images := value.([]types.ImageMeta)
images = append(images, types.ImageMeta{
ID: imgInfo.ID,
FileName: imgInfo.FileName,
Height: imgInfo.ThumbH,
Width: imgInfo.ThumbW,
ThumbSize: imgInfo.ThumbSize,
CreatedAt: imgInfo.CreatedAt.Format(constant.TimeFormat),
URL: ossURL,
URL: ossUrl.String(),
Thumbnail: presignedURL.String(),
})
groupedImages.Store(date, images)
return nil
})
}
@@ -192,8 +195,17 @@ func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.Sca
return nil, err
}
// 转换为切片并排序
var imageList []types.AllImageDetail
groupedImages.Range(func(key, value interface{}) bool {
imageList = append(imageList, types.AllImageDetail{
Date: key.(string),
List: value.([]types.ImageMeta),
})
return true
})
return &types.QueryShareImageResponse{
Records: ResultList}, nil
Records: imageList}, nil
}
func (l *QueryShareImageLogic) recordUserVisit(shareID int64, userID string) error {
@@ -255,63 +267,3 @@ func (l *QueryShareImageLogic) incrementVisitCount(shareCode string, limit int64
return nil
}
// 提取解密操作为函数
func (l *QueryShareImageLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *QueryShareImageLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -9,7 +9,6 @@ import (
"fmt"
"github.com/ccpwcn/kgo"
"github.com/minio/minio-go/v7"
"github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/core/logx"
"golang.org/x/sync/errgroup"
"image"
@@ -20,8 +19,6 @@ import (
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"strconv"
"time"
)
@@ -76,7 +73,7 @@ func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) (
for _, img := range req.Images {
img := img // 确保每个协程有独立的 img 参数副本
g.Go(func() error {
return l.uploadImageAndRecord(tx, uid, album, img, req)
return l.uploadImageAndRecord(tx, uid, album, img)
})
}
@@ -101,8 +98,6 @@ func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) (
ValidityPeriod: int64(duration),
ExpireTime: expiryTime,
ImageCount: int64(len(req.Images)),
Provider: req.Provider,
Bucket: req.Bucket,
}
err = tx.ScaStorageShare.Create(&storageShare)
if err != nil {
@@ -130,33 +125,30 @@ func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) (
return storageShare.InviteCode, nil
}
func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid string, album model.ScaStorageAlbum, img types.ShareImageMeta, req *types.ShareImageRequest) error {
func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid string, album model.ScaStorageAlbum, img types.ShareImageMeta) error {
// 上传原始图片到用户的存储桶
// 上传原始图片到存储桶
originImage, err := base64.StdEncoding.DecodeString(img.OriginImage)
if err != nil {
return fmt.Errorf("base64 decode failed: %v", err)
}
originObjectKey := path.Join(
"share_space",
uid,
time.Now().Format("2006/01"),
fmt.Sprintf("%s_%s%s", img.FileName, kgo.SimpleUuid(), filepath.Ext(img.FileName)),
)
// 获取存储服务
ossConfig, err := l.getOssConfigFromCacheOrDb(constant.UserOssConfigPrefix+uid+":"+req.Provider, uid, req.Provider)
_, err = l.svcCtx.MinioClient.PutObject(
l.ctx,
constant.ShareImagesBucketName,
originObjectKey,
bytes.NewReader(originImage),
int64(len(originImage)),
minio.PutObjectOptions{
ContentType: "image/jpeg",
},
)
if err != nil {
return err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return errors.New("get storage failed")
}
_, err = service.UploadFileSimple(l.ctx, ossConfig.BucketName, originObjectKey, bytes.NewReader(originImage), map[string]string{
"Content-Type": img.FileType,
})
if err != nil {
logx.Errorf("Failed to upload object to storage: %v", err)
logx.Errorf("Failed to upload object to MinIO: %v", err)
return err
}
@@ -169,8 +161,6 @@ func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid stri
// 记录原始图片信息
imageRecord := model.ScaStorageInfo{
UserID: uid,
Provider: req.Provider,
Bucket: req.Bucket,
Path: originObjectKey,
FileName: img.FileName,
FileSize: strconv.Itoa(size),
@@ -197,14 +187,7 @@ func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid stri
l.classifyFile(img.FileType),
fmt.Sprintf("%s_%s.jpg", time.Now().Format("20060102150405"), kgo.SimpleUuid()),
)
exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName)
if err != nil || !exists {
err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
if err != nil {
logx.Errorf("Failed to create MinIO bucket: %v", err)
return err
}
}
_, err = l.svcCtx.MinioClient.PutObject(
l.ctx,
constant.ThumbnailBucketName,
@@ -257,66 +240,6 @@ func (l *UploadShareImageLogic) GetImageInfo(base64Str string) (width, height in
return imgCfg.Width, imgCfg.Height, size, nil
}
// 提取解密操作为函数
func (l *UploadShareImageLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *UploadShareImageLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}
// GenerateExpiryTime 函数接受当前时间和有效期(天为单位),返回过期时间
func (l *UploadShareImageLogic) GenerateExpiryTime(currentTime time.Time, durationInDays int) time.Time {
// 创建一个持续时间对象

View File

@@ -24,7 +24,7 @@ func NewDownloadAlbumLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Dow
}
func (l *DownloadAlbumLogic) DownloadAlbum(req *types.DownloadAlbumRequest) (resp string, err error) {
// todo: add your logic here and delete this line
// todo: download album logic
return
}

View File

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"gorm.io/gen"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
@@ -63,6 +64,14 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
// 数据库查询文件信息列表
var storageInfoQuery query.IScaStorageInfoDo
var storageInfoList []types.FileInfoResult
var queryCondition []gen.Condition
queryCondition = append(queryCondition, storageInfo.UserID.Eq(uid))
queryCondition = append(queryCondition, storageInfo.AlbumID.Eq(req.ID))
// 类型筛选 1 是分享类型
if req.Type != constant.AlbumTypeShared {
queryCondition = append(queryCondition, storageInfo.Provider.Eq(req.Provider))
queryCondition = append(queryCondition, storageInfo.Bucket.Eq(req.Bucket))
}
storageInfoQuery = storageInfo.Select(
storageInfo.ID,
@@ -74,11 +83,7 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
storageThumb.ThumbH,
storageThumb.ThumbSize).
LeftJoin(storageThumb, storageInfo.ID.EqCol(storageThumb.InfoID)).
Where(
storageInfo.UserID.Eq(uid),
storageInfo.Provider.Eq(req.Provider),
storageInfo.Bucket.Eq(req.Bucket),
storageInfo.AlbumID.Eq(req.ID)).
Where(queryCondition...).
Order(storageInfo.CreatedAt.Desc())
err = storageInfoQuery.Scan(&storageInfoList)
if err != nil {
@@ -103,24 +108,41 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
// 按日期进行分组
var wg sync.WaitGroup
groupedImages := sync.Map{}
reqParams := make(url.Values)
for _, dbFileInfo := range storageInfoList {
wg.Add(1)
go func(dbFileInfo *types.FileInfoResult) {
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
if err != nil {
logx.Error(err)
return
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
if err != nil {
logx.Error(err)
return
var thumbnailUrl string
var originalUrl string
if req.Type == constant.AlbumTypeShared {
minioOriginalUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ShareImagesBucketName, dbFileInfo.Path, 30*time.Minute, reqParams)
originalUrl = minioOriginalUrl.String()
if err != nil {
return
}
minioThumbnailUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, 30*time.Minute, reqParams)
thumbnailUrl = minioThumbnailUrl.String()
if err != nil {
return
}
} else {
thumbnailUrl, err = service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return
}
originalUrl, err = service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return
}
}
// 使用 Load 或 Store 确保原子操作
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
images := value.([]types.ImageMeta)
@@ -128,8 +150,8 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
URL: url,
Thumbnail: thumbnailUrl,
URL: originalUrl,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),

View File

@@ -39,10 +39,10 @@ func (l *GetAlbumListLogic) GetAlbumList(req *types.AlbumListRequest) (resp *typ
orderConditions = append(orderConditions, storageAlbum.AlbumName.Desc())
}
var typeConditions []gen.Condition
typeConditions = append(typeConditions, storageAlbum.UserID.Eq(uid))
if req.Type != -1 {
// 获取全部相册
typeConditions = append(typeConditions, storageAlbum.AlbumType.Eq(req.Type))
typeConditions = append(typeConditions, storageAlbum.UserID.Eq(uid))
}
albums, err := storageAlbum.Where(
typeConditions...).

View File

@@ -7,7 +7,6 @@ import (
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
@@ -108,13 +107,12 @@ func (l *GetDeleteRecordLogic) GetDeleteRecord(req *types.QueryDeleteRecordReque
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return
@@ -126,7 +124,7 @@ func (l *GetDeleteRecordLogic) GetDeleteRecord(req *types.QueryDeleteRecordReque
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
Thumbnail: thumbnailUrl,
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,

View File

@@ -7,7 +7,6 @@ import (
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
@@ -106,13 +105,13 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return
@@ -125,7 +124,7 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
Thumbnail: thumbnailUrl,
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,

View File

@@ -11,7 +11,6 @@ import (
"golang.org/x/sync/semaphore"
"gorm.io/gen"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
@@ -135,13 +134,12 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
defer sem.Release(1)
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return err
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return err
@@ -153,7 +151,7 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
Thumbnail: thumbnailUrl,
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,

View File

@@ -7,7 +7,6 @@ import (
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
@@ -112,13 +111,12 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return
@@ -130,7 +128,7 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
Thumbnail: thumbnailUrl,
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,

View File

@@ -2,12 +2,16 @@ package storage
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
"github.com/redis/go-redis/v9"
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
"time"
"github.com/zeromicro/go-zero/core/logx"
@@ -54,6 +58,18 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location
return nil, err
}
// 加载用户oss配置信息
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
locationMap := make(map[string][]types.LocationMeta)
for _, loc := range locations {
@@ -68,16 +84,16 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location
if city == "" {
city = loc.Country
}
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, loc.CoverImage, 15*time.Minute, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, loc.CoverImage, time.Minute*30)
if err != nil {
return nil, errors.New("get presigned url failed")
logx.Error(err)
return nil, err
}
locationMeta := types.LocationMeta{
ID: loc.ID,
City: city,
Total: loc.Total,
CoverImage: presignedUrl.String(),
CoverImage: thumbnailUrl,
}
locationMap[locationKey] = append(locationMap[locationKey], locationMeta)
}
@@ -93,3 +109,63 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location
return &types.LocationListResponse{Records: locationListData}, nil
}
// 提取解密操作为函数
func (l *QueryLocationImageListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt access key failed")
}
secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key)
if err != nil {
return nil, errors.New("decrypt secret key failed")
}
return &storageConfig.StorageConfig{
Provider: config.Provider,
Endpoint: config.Endpoint,
AccessKey: accessKey,
SecretKey: secretKey,
BucketName: config.Bucket,
Region: config.Region,
}, nil
}
// 从缓存或数据库中获取 OSS 配置
func (l *QueryLocationImageListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) {
result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
if err != nil && !errors.Is(err, redis.Nil) {
return nil, errors.New("get oss config failed")
}
var ossConfig *storageConfig.StorageConfig
if result != "" {
var redisOssConfig model.ScaStorageConfig
if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil {
return nil, errors.New("unmarshal oss config failed")
}
return l.decryptConfig(&redisOssConfig)
}
// 缓存未命中,从数据库中加载
scaOssConfig := l.svcCtx.DB.ScaStorageConfig
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
if err != nil {
return nil, err
}
// 缓存数据库配置
ossConfig, err = l.decryptConfig(dbOssConfig)
if err != nil {
return nil, err
}
marshalData, err := json.Marshal(dbOssConfig)
if err != nil {
return nil, errors.New("marshal oss config failed")
}
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err()
if err != nil {
return nil, errors.New("set oss config failed")
}
return ossConfig, nil
}

View File

@@ -9,7 +9,6 @@ import (
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
@@ -119,13 +118,12 @@ func (l *QueryRecentImageListLogic) QueryRecentImageList(req *types.RecentListRe
defer sem.Release(1)
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return err
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return err
@@ -137,7 +135,7 @@ func (l *QueryRecentImageListLogic) QueryRecentImageList(req *types.RecentListRe
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
Thumbnail: thumbnailUrl,
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,

View File

@@ -7,7 +7,6 @@ import (
"fmt"
"github.com/redis/go-redis/v9"
"math/rand"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/app/auth/model/mysql/query"
"schisandra-album-cloud-microservices/common/constant"
@@ -112,13 +111,12 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL
defer wg.Done()
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams)
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return
}
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
if err != nil {
logx.Error(err)
return
@@ -130,7 +128,7 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL
images = append(images, types.ImageMeta{
ID: dbFileInfo.ID,
FileName: dbFileInfo.FileName,
Thumbnail: presignedUrl.String(),
Thumbnail: thumbnailUrl,
URL: url,
Width: dbFileInfo.ThumbW,
Height: dbFileInfo.ThumbH,

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"github.com/redis/go-redis/v9"
"net/url"
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
"schisandra-album-cloud-microservices/common/constant"
"schisandra-album-cloud-microservices/common/encrypt"
@@ -65,16 +64,16 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque
}
// 加载用户oss配置信息
//cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
//ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
//if err != nil {
// return nil, err
//}
//
//service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
//if err != nil {
// return nil, errors.New("get storage failed")
//}
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider)
if err != nil {
return nil, err
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return nil, errors.New("get storage failed")
}
categoryMap := sync.Map{}
tagCountMap := sync.Map{}
@@ -97,11 +96,12 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque
// 为每个 Tag 存储封面图片路径
if _, exists := tagCoverMap.Load(tagKey); !exists {
// 使用服务生成预签名 URL
reqParams := make(url.Values)
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, info.ThumbPath, time.Hour*24*7, reqParams)
if err == nil {
tagCoverMap.Store(tagKey, presignedUrl.String())
thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, info.ThumbPath, time.Minute*30)
if err != nil {
logx.Error(err)
return nil, errors.New("get presigned url failed")
}
tagCoverMap.Store(tagKey, thumbnailUrl)
}
}

View File

@@ -46,6 +46,7 @@ func (l *SetStorageConfigLogic) SetStorageConfig(req *types.StorageConfigRequest
AccessKey: accessKey,
SecretKey: secretKey,
Region: req.Region,
Capacity: req.Capacity,
}
err = l.svcCtx.DB.ScaStorageConfig.Create(ossConfig)
if err != nil {

View File

@@ -87,8 +87,6 @@ func (l *ShareAlbumLogic) ShareAlbum(req *types.ShareAlbumRequest) (resp string,
AccessPassword: req.AccessPassword,
VisitLimit: req.AccessLimit,
ImageCount: imageCount,
Provider: req.Provider,
Bucket: req.Bucket,
Status: 0,
}
err = storageShare.Create(storageShareInfo)

View File

@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"github.com/ccpwcn/kgo"
"github.com/minio/minio-go/v7"
"github.com/redis/go-redis/v9"
"github.com/zeromicro/go-zero/core/logx"
"golang.org/x/sync/errgroup"
@@ -79,9 +78,9 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
// 使用 `errgroup.Group` 处理并发任务
var (
faceId int64
filePath string
minioFilePath string
faceId int64
filePath string
thumbPath string
)
g, ctx := errgroup.WithContext(context.Background())
// 创建信号量,限制最大并发上传数(比如最多同时 5 个任务)
@@ -119,26 +118,12 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
Closer: io.NopCloser(nil),
}
fileUrl, err := l.uploadFileToOSS(uid, header, fileReader, result)
fileUrl, thumbUrl, err := l.uploadFileToOSS(uid, header, fileReader, thumbnail, result)
if err != nil {
return err
}
filePath = fileUrl
return nil
})
// 上传缩略图到 MinIO
g.Go(func() error {
if err := sem.Acquire(ctx, 1); err != nil {
return err
}
defer sem.Release(1)
path, err := l.uploadFileToMinio(uid, header, thumbnail, result)
if err != nil {
return err
}
minioFilePath = path
thumbPath = thumbUrl
return nil
})
@@ -149,11 +134,11 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
fileUploadMessage := &types.FileUploadMessage{
UID: uid,
Data: result,
Result: result,
FaceID: faceId,
FileHeader: header,
FilePath: filePath,
ThumbPath: minioFilePath,
ThumbPath: thumbPath,
}
// 转换为 JSON
messageData, err := json.Marshal(fileUploadMessage)
@@ -205,19 +190,19 @@ func (l *UploadFileLogic) parseImageInfoResult(r *http.Request) (types.File, err
}
// 上传文件到 OSS
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, error) {
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, thumbnail multipart.File, result types.File) (string, string, error) {
cacheKey := constant.UserOssConfigPrefix + uid + ":" + result.Provider
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheKey, uid, result.Provider)
if err != nil {
return "", errors.New("get oss config failed")
return "", "", errors.New("get oss config failed")
}
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
if err != nil {
return "", errors.New("get storage failed")
return "", "", errors.New("get storage failed")
}
objectKey := path.Join(
"image_space",
constant.ImageSpace,
uid,
time.Now().Format("2006/01"), // 按年/月划分目录
l.classifyFile(result.FileType, result.IsScreenshot),
@@ -228,52 +213,62 @@ func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHead
"Content-Type": header.Header.Get("Content-Type"),
})
if err != nil {
return "", errors.New("upload file failed")
return "", "", errors.New("upload file failed")
}
//url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, objectKey, time.Hour*24*7)
//if err != nil {
// return "", "", errors.New("presigned url failed")
//}
return objectKey, nil
}
func (l *UploadFileLogic) uploadFileToMinio(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, error) {
objectKey := path.Join(
// 上传缩略图
thumbObjectKey := path.Join(
constant.ThumbnailSpace,
uid,
time.Now().Format("2006/01"), // 按年/月划分目录
l.classifyFile(result.FileType, result.IsScreenshot),
fmt.Sprintf("%s_%s%s", strings.TrimSuffix(header.Filename, filepath.Ext(header.Filename)), kgo.SimpleUuid(), filepath.Ext(header.Filename)),
)
exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName)
if err != nil || !exists {
err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
if err != nil {
logx.Errorf("Failed to create MinIO bucket: %v", err)
return "", err
}
}
// 上传到MinIO
_, err = l.svcCtx.MinioClient.PutObject(
l.ctx,
constant.ThumbnailBucketName,
objectKey,
file,
int64(result.ThumbSize),
minio.PutObjectOptions{
ContentType: result.FileType,
},
)
_, err = service.UploadFileSimple(l.ctx, ossConfig.BucketName, thumbObjectKey, thumbnail, map[string]string{
"Content-Type": header.Header.Get("Content-Type"),
})
if err != nil {
return "", err
return "", "", errors.New("upload thumbnail file failed")
}
//reqParams := make(url.Values)
//presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, objectKey, time.Hour*24*7, reqParams)
//if err != nil {
// return "", "", err
//}
return objectKey, nil
return objectKey, thumbObjectKey, nil
}
//func (l *UploadFileLogic) uploadFileToMinio(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, error) {
// objectKey := path.Join(
// uid,
// time.Now().Format("2006/01"), // 按年/月划分目录
// l.classifyFile(result.FileType, result.IsScreenshot),
// fmt.Sprintf("%s_%s%s", strings.TrimSuffix(header.Filename, filepath.Ext(header.Filename)), kgo.SimpleUuid(), filepath.Ext(header.Filename)),
// )
// exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName)
// if err != nil || !exists {
// err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true})
// if err != nil {
// logx.Errorf("Failed to create MinIO bucket: %v", err)
// return "", err
// }
// }
// // 上传到MinIO
// _, err = l.svcCtx.MinioClient.PutObject(
// l.ctx,
// constant.ThumbnailBucketName,
// objectKey,
// file,
// int64(result.ThumbSize),
// minio.PutObjectOptions{
// ContentType: result.FileType,
// },
// )
// if err != nil {
// return "", err
// }
// //reqParams := make(url.Values)
// //presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, objectKey, time.Hour*24*7, reqParams)
// //if err != nil {
// // return "", "", err
// //}
// return objectKey, nil
//}
// 提取解密操作为函数
func (l *UploadFileLogic) decryptConfig(dbConfig *model.ScaStorageConfig) (*config.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(dbConfig.AccessKey, l.svcCtx.Config.Encrypt.Key)
@@ -352,14 +347,15 @@ func (l *UploadFileLogic) classifyFile(mimeType string, isScreenshot bool) strin
"video/x-matroska": "video",
}
// 如果isScreenshot为true则返回"screenshot"
if isScreenshot {
return "screenshot"
}
// 根据MIME类型从map中获取分类
if classification, exists := typeMap[mimeType]; exists {
return classification
}
// 如果isScreenshot为true则返回"screenshot"
if isScreenshot {
return "screenshot"
}
return "unknown"
}

View File

@@ -49,36 +49,28 @@ func (c *NsqImageProcessConsumer) HandleMessage(msg *nsq.Message) error {
}
// 根据 GPS 信息获取地理位置信息
country, province, city, err := c.getGeoLocation(message.Data.Latitude, message.Data.Longitude)
country, province, city, err := c.getGeoLocation(message.Result.Latitude, message.Result.Longitude)
if err != nil {
return err
}
// 将地址信息保存到数据库
locationId, err := c.saveFileLocationInfoToDB(message.UID, message.Data.Latitude, message.Data.Longitude, country, province, city, message.ThumbPath)
locationId, err := c.saveFileLocationInfoToDB(message.UID, message.Result.Latitude, message.Result.Longitude, country, province, city, message.ThumbPath)
if err != nil {
return err
}
// 将文件信息存入数据库
storageId, err := c.saveFileInfoToDB(message.UID, message.Data.Bucket, message.Data.Provider, message.FileHeader, message.Data, message.FaceID, message.FilePath, locationId, message.Data.AlbumId)
storageId, err := c.saveFileInfoToDB(message.UID, message.Result.Bucket, message.Result.Provider, message.FileHeader, message.Result, message.FaceID, message.FilePath, locationId, message.Result.AlbumId)
if err != nil {
return err
}
err = c.saveFileThumbnailInfoToDB(message.UID, message.ThumbPath, message.Data.ThumbW, message.Data.ThumbH, message.Data.ThumbSize, storageId)
err = c.saveFileThumbnailInfoToDB(message.UID, message.ThumbPath, message.Result.ThumbW, message.Result.ThumbH, message.Result.ThumbSize, storageId)
if err != nil {
return err
}
// 删除缓存
c.afterImageUpload(message.UID)
// redis 保存最近7天上传的文件列表
//err = c.saveRecentFileList(message.UID, message.Thumbnail, message.URL, storageId, message.Data, message.FileHeader.Filename)
//if err != nil {
// return err
//}
return nil
}
@@ -166,32 +158,6 @@ func (c *NsqImageProcessConsumer) classifyFile(mimeType string, isScreenshot boo
return "unknown"
}
//// 保存最近7天上传的文件列表
//func (c *NsqImageProcessConsumer) saveRecentFileList(uid, thumbnail, url string, id int64, result types.File, filename string) error {
//
// redisKey := constant.ImageRecentPrefix + uid + ":" + strconv.FormatInt(id, 10)
// imageMeta := types.ImageMeta{
// ID: id,
// URL: url,
// FileName: filename,
// Width: result.ThumbW,
// Height: result.ThumbH,
// Thumbnail: thumbnail,
// CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
// }
// marshal, err := json.Marshal(imageMeta)
// if err != nil {
// logx.Error(err)
// return errors.New("marshal image meta failed")
// }
// err = c.svcCtx.RedisClient.Set(c.ctx, redisKey, marshal, time.Hour*24*7).Err()
// if err != nil {
// logx.Error(err)
// return errors.New("save recent file list failed")
// }
// return nil
//}
// 提取解密操作为函数
func (c *NsqImageProcessConsumer) decryptConfig(dbConfig *model.ScaStorageConfig) (*config.StorageConfig, error) {
accessKey, err := encrypt.Decrypt(dbConfig.AccessKey, c.svcCtx.Config.Encrypt.Key)

View File

@@ -29,7 +29,7 @@ type File struct {
type FileUploadMessage struct {
FaceID int64 `json:"face_id"`
FileHeader *multipart.FileHeader `json:"fileHeader"`
Data File `json:"data"`
Result File `json:"result"`
UID string `json:"uid"`
FilePath string `json:"filePath"`
URL string `json:"url"`

View File

@@ -35,6 +35,7 @@ type AlbumDetailListRequest struct {
ID int64 `json:"id"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
Type int64 `json:"type"`
}
type AlbumDetailListResponse struct {
@@ -298,7 +299,7 @@ type QueryShareImageRequest struct {
}
type QueryShareImageResponse struct {
Records []ShareImageListMeta `json:"records"`
Records []AllImageDetail `json:"records"`
}
type QueryShareInfoRequest struct {
@@ -371,17 +372,6 @@ type ShareAlbumRequest struct {
Bucket string `json:"bucket"`
}
type ShareImageListMeta struct {
ID int64 `json:"id"`
FileName string `json:"file_name"`
URL string `json:"url"`
Thumbnail string `json:"thumbnail"`
Width float64 `json:"width"`
Height float64 `json:"height"`
ThumbSize float64 `json:"thumb_size"`
CreatedAt string `json:"created_at"`
}
type ShareImageMeta struct {
FileName string `json:"file_name"`
OriginImage string `json:"origin_image"`
@@ -397,8 +387,6 @@ type ShareImageRequest struct {
ExpireDate string `json:"expire_date"`
AccessLimit int64 `json:"access_limit,omitempty"`
AccessPassword string `json:"access_password,omitempty"`
Provider string `json:"provider"`
Bucket string `json:"bucket"`
Images []ShareImageMeta `json:"images"`
}
@@ -480,6 +468,7 @@ type StorageConfigRequest struct {
Endpoint string `json:"endpoint"`
Bucket string `json:"bucket"`
Region string `json:"region"`
Capacity int64 `json:"capacity"`
}
type StorageListResponse struct {