✨ optimized image list interface
This commit is contained in:
@@ -53,12 +53,9 @@ func (l *FaceRecognitionLogic) FaceRecognition(in *pb.FaceRecognitionRequest) (*
|
||||
}
|
||||
// 提取人脸特征
|
||||
faceFeatures, err := l.svcCtx.FaceRecognizer.RecognizeSingle(toJPEG)
|
||||
if err != nil {
|
||||
if err != nil || faceFeatures == nil {
|
||||
return nil, err
|
||||
}
|
||||
if faceFeatures == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hashKey := constant.FaceVectorPrefix + in.GetUserId()
|
||||
// 从 Redis 加载人脸数据
|
||||
|
@@ -520,6 +520,7 @@ type (
|
||||
Width float64 `json:"width"`
|
||||
Height float64 `json:"height"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
}
|
||||
AllImageDetail {
|
||||
Date string `json:"date"`
|
||||
@@ -588,6 +589,10 @@ type (
|
||||
ThingDetailListResponse {
|
||||
records []AllImageDetail `json:"records"`
|
||||
}
|
||||
// 单张图片请求参数
|
||||
SingleImageRequest {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
)
|
||||
|
||||
// 文件上传
|
||||
@@ -670,5 +675,9 @@ service auth {
|
||||
// 获取事物详情列表
|
||||
@handler queryThingDetailList
|
||||
post /image/thing/detail/list (ThingDetailListRequest) returns (ThingDetailListResponse)
|
||||
|
||||
// 获取单张图片连接
|
||||
@handler getImageUrl
|
||||
post /image/url/single (SingleImageRequest) returns (string)
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/zeromicro/go-zero/core/conf"
|
||||
"github.com/zeromicro/go-zero/rest"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/mq"
|
||||
"schisandra-album-cloud-microservices/common/idgenerator"
|
||||
"schisandra-album-cloud-microservices/common/middleware"
|
||||
|
||||
@@ -31,6 +32,8 @@ func main() {
|
||||
server.Use(middleware.I18nMiddleware)
|
||||
ctx := svc.NewServiceContext(c)
|
||||
handler.RegisterHandlers(server, ctx)
|
||||
// start image process consumer
|
||||
go mq.NewImageProcessConsumer(ctx)
|
||||
// initialize id generator
|
||||
idgenerator.NewIDGenerator(0)
|
||||
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
||||
|
@@ -171,4 +171,9 @@ Minio:
|
||||
# Minio 访问密钥
|
||||
SecretAccessKey: XEHkwExqQdAlEPfpRk36xpc0Sie8hZkcmlhXQJXw
|
||||
# Minio 使用SSL
|
||||
UseSSL: false
|
||||
UseSSL: false
|
||||
#NSQ配置
|
||||
NSQ:
|
||||
# NSQD地址
|
||||
NSQDHost: 1.95.0.111:4150
|
||||
LookUpdHost: 1.95.0.111:4161
|
||||
|
@@ -73,4 +73,8 @@ type Config struct {
|
||||
SecretAccessKey string
|
||||
UseSSL bool
|
||||
}
|
||||
NSQ struct {
|
||||
NSQDHost string
|
||||
LookUpdHost string
|
||||
}
|
||||
}
|
||||
|
@@ -268,6 +268,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/image/thing/list",
|
||||
Handler: storage.QueryThingImageListHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/image/url/single",
|
||||
Handler: storage.GetImageUrlHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/uploads",
|
||||
|
@@ -0,0 +1,29 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/storage"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
|
||||
"schisandra-album-cloud-microservices/common/xhttp"
|
||||
)
|
||||
|
||||
func GetImageUrlHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.SingleImageRequest
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
l := storage.NewGetImageUrlLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetImageUrl(&req)
|
||||
if err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
|
||||
} else {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@ 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"
|
||||
@@ -56,18 +57,28 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
|
||||
return nil, errors.New("get cached image list failed")
|
||||
}
|
||||
|
||||
// 缓存未命中,从数据库中查询
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
storageThumb := l.svcCtx.DB.ScaStorageThumb
|
||||
// 数据库查询文件信息列表
|
||||
var storageInfoQuery query.IScaStorageInfoDo
|
||||
var storageInfoList []types.FileInfoResult
|
||||
|
||||
storageInfoQuery = storageInfo.Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.AlbumID.Eq(req.ID)).
|
||||
storageInfoQuery = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageThumb.ThumbPath,
|
||||
storageThumb.ThumbW,
|
||||
storageThumb.ThumbH,
|
||||
storageThumb.ThumbSize).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).
|
||||
Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.AlbumID.Eq(req.ID)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
storageInfoList, err := storageInfoQuery.Find()
|
||||
err = storageInfoQuery.Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -75,17 +86,17 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
|
||||
return &types.AlbumDetailListResponse{}, nil
|
||||
}
|
||||
|
||||
// 加载用户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")
|
||||
}
|
||||
//// 加载用户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")
|
||||
//}
|
||||
|
||||
// 按日期进行分组
|
||||
var wg sync.WaitGroup
|
||||
@@ -93,11 +104,12 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
|
||||
|
||||
for _, dbFileInfo := range storageInfoList {
|
||||
wg.Add(1)
|
||||
go func(dbFileInfo *model.ScaStorageInfo) {
|
||||
go func(dbFileInfo *types.FileInfoResult) {
|
||||
defer wg.Done()
|
||||
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
|
||||
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
|
||||
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7)
|
||||
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
|
||||
@@ -109,15 +121,15 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
|
||||
images = append(images, types.ImageMeta{
|
||||
ID: dbFileInfo.ID,
|
||||
FileName: dbFileInfo.FileName,
|
||||
URL: url,
|
||||
Width: dbFileInfo.Width,
|
||||
Height: dbFileInfo.Height,
|
||||
URL: presignedUrl.String(),
|
||||
Width: dbFileInfo.ThumbW,
|
||||
Height: dbFileInfo.ThumbH,
|
||||
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
groupedImages.Store(date, images)
|
||||
}(dbFileInfo)
|
||||
}(&dbFileInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
var imageList []types.AllImageDetail
|
||||
|
@@ -7,8 +7,8 @@ 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"
|
||||
"schisandra-album-cloud-microservices/common/encrypt"
|
||||
storageConfig "schisandra-album-cloud-microservices/common/storage/config"
|
||||
@@ -58,16 +58,24 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ
|
||||
|
||||
// 缓存未命中,从数据库中查询
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
// 数据库查询文件信息列表
|
||||
var storageInfoQuery query.IScaStorageInfoDo
|
||||
storageThumb := l.svcCtx.DB.ScaStorageThumb
|
||||
var storageInfoList []types.FileInfoResult
|
||||
|
||||
storageInfoQuery = storageInfo.Where(
|
||||
err = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageInfo.Path,
|
||||
storageThumb.ThumbPath,
|
||||
storageThumb.ThumbW,
|
||||
storageThumb.ThumbH,
|
||||
storageThumb.ThumbSize).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.FaceID.Eq(req.FaceID)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
storageInfoList, err := storageInfoQuery.Find()
|
||||
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -93,15 +101,22 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ
|
||||
|
||||
for _, dbFileInfo := range storageInfoList {
|
||||
wg.Add(1)
|
||||
go func(dbFileInfo *model.ScaStorageInfo) {
|
||||
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
|
||||
}
|
||||
|
||||
// 使用 Load 或 Store 确保原子操作
|
||||
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
|
||||
images := value.([]types.ImageMeta)
|
||||
@@ -109,15 +124,16 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ
|
||||
images = append(images, types.ImageMeta{
|
||||
ID: dbFileInfo.ID,
|
||||
FileName: dbFileInfo.FileName,
|
||||
Thumbnail: presignedUrl.String(),
|
||||
URL: url,
|
||||
Width: dbFileInfo.Width,
|
||||
Height: dbFileInfo.Height,
|
||||
Width: dbFileInfo.ThumbW,
|
||||
Height: dbFileInfo.ThumbH,
|
||||
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
groupedImages.Store(date, images)
|
||||
}(dbFileInfo)
|
||||
}(&dbFileInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
var imageList []types.AllImageDetail
|
||||
|
148
app/auth/api/internal/logic/storage/get_image_url_logic.go
Normal file
148
app/auth/api/internal/logic/storage/get_image_url_logic.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"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"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetImageUrlLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetImageUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetImageUrlLogic {
|
||||
return &GetImageUrlLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetImageUrlLogic) GetImageUrl(req *types.SingleImageRequest) (resp string, err error) {
|
||||
uid, ok := l.ctx.Value("user_id").(string)
|
||||
if !ok {
|
||||
return "", errors.New("user_id not found")
|
||||
}
|
||||
|
||||
// 从redis 获取url
|
||||
cacheKey := constant.ImageSinglePrefix + uid + ":" + strconv.FormatInt(req.ID, 10)
|
||||
cacheUrl, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result()
|
||||
if err != nil && !errors.Is(err, redis.Nil) {
|
||||
logx.Info(err)
|
||||
return "", errors.New("get image url failed")
|
||||
}
|
||||
if cacheUrl != "" {
|
||||
return cacheUrl, nil
|
||||
}
|
||||
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
result, err := storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.Provider,
|
||||
storageInfo.Bucket,
|
||||
storageInfo.Path).
|
||||
Where(storageInfo.ID.Eq(req.ID), storageInfo.UserID.Eq(uid)).
|
||||
First()
|
||||
if err != nil {
|
||||
logx.Info(err)
|
||||
return "", errors.New("get storage info failed")
|
||||
}
|
||||
if result == nil {
|
||||
return "", errors.New("get storage info failed")
|
||||
}
|
||||
// 加载用户oss配置信息
|
||||
cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + result.Provider
|
||||
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, result.Provider)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig)
|
||||
if err != nil {
|
||||
return "", errors.New("get storage failed")
|
||||
}
|
||||
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, result.Path, 7*24*time.Hour)
|
||||
if err != nil {
|
||||
return "", errors.New("get presigned url failed")
|
||||
}
|
||||
// 缓存url
|
||||
err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, url, 7*24*time.Hour).Err()
|
||||
if err != nil {
|
||||
logx.Info(err)
|
||||
}
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// 提取解密操作为函数
|
||||
func (l *GetImageUrlLogic) 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 *GetImageUrlLogic) 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
|
||||
}
|
@@ -8,10 +8,10 @@ import (
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"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"
|
||||
"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"
|
||||
@@ -66,25 +66,44 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
|
||||
|
||||
// 缓存未命中,从数据库中查询
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
// 数据库查询文件信息列表
|
||||
var storageInfoQuery query.IScaStorageInfoDo
|
||||
storageThumb := l.svcCtx.DB.ScaStorageThumb
|
||||
var storageInfoList []types.FileInfoResult
|
||||
if req.Sort {
|
||||
storageInfoQuery = storageInfo.Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Eq(req.Type),
|
||||
storageInfo.AlbumID.IsNull()).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
err = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageInfo.Path,
|
||||
storageThumb.ThumbPath,
|
||||
storageThumb.ThumbW,
|
||||
storageThumb.ThumbH,
|
||||
storageThumb.ThumbSize).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).
|
||||
Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Eq(req.Type),
|
||||
storageInfo.AlbumID.IsNull()).
|
||||
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
|
||||
} else {
|
||||
storageInfoQuery = storageInfo.Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Eq(req.Type)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
err = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageThumb.ThumbPath,
|
||||
storageInfo.Path,
|
||||
storageThumb.ThumbW,
|
||||
storageThumb.ThumbH,
|
||||
storageThumb.ThumbSize).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).
|
||||
Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Eq(req.Type)).
|
||||
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
|
||||
}
|
||||
storageInfoList, err := storageInfoQuery.Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -110,10 +129,16 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
|
||||
|
||||
for _, dbFileInfo := range storageInfoList {
|
||||
wg.Add(1)
|
||||
go func(dbFileInfo *model.ScaStorageInfo) {
|
||||
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)
|
||||
@@ -126,15 +151,16 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
|
||||
images = append(images, types.ImageMeta{
|
||||
ID: dbFileInfo.ID,
|
||||
FileName: dbFileInfo.FileName,
|
||||
Thumbnail: presignedUrl.String(),
|
||||
URL: url,
|
||||
Width: dbFileInfo.Width,
|
||||
Height: dbFileInfo.Height,
|
||||
Width: dbFileInfo.ThumbW,
|
||||
Height: dbFileInfo.ThumbH,
|
||||
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
groupedImages.Store(date, images)
|
||||
}(dbFileInfo)
|
||||
}(&dbFileInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
var imageList []types.AllImageDetail
|
||||
|
@@ -7,6 +7,7 @@ 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"
|
||||
@@ -56,18 +57,28 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati
|
||||
return nil, errors.New("get cached image list failed")
|
||||
}
|
||||
|
||||
// 缓存未命中,从数据库中查询
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
storageThumb := l.svcCtx.DB.ScaStorageThumb
|
||||
// 数据库查询文件信息列表
|
||||
var storageInfoQuery query.IScaStorageInfoDo
|
||||
var storageInfoList []types.FileInfoResult
|
||||
|
||||
storageInfoQuery = storageInfo.Where(
|
||||
storageInfoQuery = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageThumb.ThumbPath,
|
||||
storageInfo.Path,
|
||||
storageThumb.ThumbW,
|
||||
storageThumb.ThumbH,
|
||||
storageThumb.ThumbSize).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.LocationID.Eq(req.ID)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
storageInfoList, err := storageInfoQuery.Find()
|
||||
err = storageInfoQuery.Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -93,10 +104,16 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati
|
||||
|
||||
for _, dbFileInfo := range storageInfoList {
|
||||
wg.Add(1)
|
||||
go func(dbFileInfo *model.ScaStorageInfo) {
|
||||
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)
|
||||
@@ -109,15 +126,16 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati
|
||||
images = append(images, types.ImageMeta{
|
||||
ID: dbFileInfo.ID,
|
||||
FileName: dbFileInfo.FileName,
|
||||
Thumbnail: presignedUrl.String(),
|
||||
URL: url,
|
||||
Width: dbFileInfo.Width,
|
||||
Height: dbFileInfo.Height,
|
||||
Width: dbFileInfo.ThumbW,
|
||||
Height: dbFileInfo.ThumbH,
|
||||
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
groupedImages.Store(date, images)
|
||||
}(dbFileInfo)
|
||||
}(&dbFileInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
var imageList []types.AllImageDetail
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"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"
|
||||
@@ -53,16 +54,16 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location
|
||||
}
|
||||
|
||||
// 加载用户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")
|
||||
//}
|
||||
locationMap := make(map[string][]types.LocationMeta)
|
||||
|
||||
for _, loc := range locations {
|
||||
@@ -77,7 +78,8 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location
|
||||
if city == "" {
|
||||
city = loc.Country
|
||||
}
|
||||
url, err := service.PresignedURL(l.ctx, req.Bucket, loc.CoverImage, 7*24*time.Hour)
|
||||
reqParams := make(url.Values)
|
||||
presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, loc.CoverImage, 7*24*time.Hour, reqParams)
|
||||
if err != nil {
|
||||
return nil, errors.New("get presigned url failed")
|
||||
}
|
||||
@@ -85,7 +87,7 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location
|
||||
ID: loc.ID,
|
||||
City: city,
|
||||
Total: loc.Total,
|
||||
CoverImage: url,
|
||||
CoverImage: presignedUrl.String(),
|
||||
}
|
||||
locationMap[locationKey] = append(locationMap[locationKey], locationMeta)
|
||||
}
|
||||
|
@@ -62,37 +62,34 @@ func (l *QueryRecentImageListLogic) QueryRecentImageList() (resp *types.RecentLi
|
||||
if cmd == nil {
|
||||
continue
|
||||
}
|
||||
val, ok := cmd.(string)
|
||||
if !ok {
|
||||
logx.Error("invalid value type")
|
||||
return nil, errors.New("invalid value type")
|
||||
}
|
||||
var imageMeta types.ImageMeta
|
||||
err = json.Unmarshal([]byte(val), &imageMeta)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return nil, errors.New("unmarshal recent file list failed")
|
||||
}
|
||||
parse, err := time.Parse("2006-01-02 15:04:05", imageMeta.CreatedAt)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return nil, errors.New("parse recent file list failed")
|
||||
}
|
||||
date := parse.Format("2006年1月2日 星期" + WeekdayMap[parse.Weekday()])
|
||||
// 使用LoadOrStore来检查并存储或者追加
|
||||
wg.Add(1)
|
||||
go func(cmd interface{}) {
|
||||
go func(date string, imageMeta types.ImageMeta) {
|
||||
defer wg.Done()
|
||||
val, ok := cmd.(string)
|
||||
if !ok {
|
||||
logx.Error("invalid value type")
|
||||
return
|
||||
value, loaded := groupedImages.LoadOrStore(date, []types.ImageMeta{imageMeta})
|
||||
if loaded {
|
||||
images := value.([]types.ImageMeta)
|
||||
images = append(images, imageMeta)
|
||||
groupedImages.Store(date, images)
|
||||
}
|
||||
var imageMeta types.ImageMeta
|
||||
err = json.Unmarshal([]byte(val), &imageMeta)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return
|
||||
}
|
||||
parse, err := time.Parse("2006-01-02 15:04:05", imageMeta.CreatedAt)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return
|
||||
}
|
||||
date := parse.Format("2006年1月2日 星期" + WeekdayMap[parse.Weekday()])
|
||||
groupedImages.Range(func(key, value interface{}) bool {
|
||||
if key == date {
|
||||
images := value.([]types.ImageMeta)
|
||||
images = append(images, imageMeta)
|
||||
groupedImages.Store(date, images)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
groupedImages.Store(date, []types.ImageMeta{imageMeta})
|
||||
}(cmd)
|
||||
}(date, imageMeta)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
@@ -7,6 +7,7 @@ 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"
|
||||
@@ -56,18 +57,29 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL
|
||||
return nil, errors.New("get cached image list failed")
|
||||
}
|
||||
|
||||
// 缓存未命中,从数据库中查询
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
storageThumb := l.svcCtx.DB.ScaStorageThumb
|
||||
// 数据库查询文件信息列表
|
||||
var storageInfoQuery query.IScaStorageInfoDo
|
||||
var storageInfoList []types.FileInfoResult
|
||||
|
||||
storageInfoQuery = storageInfo.Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Tag.Eq(req.TagName)).
|
||||
storageInfoQuery = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageThumb.ThumbPath,
|
||||
storageInfo.Path,
|
||||
storageThumb.ThumbW,
|
||||
storageThumb.ThumbH,
|
||||
storageThumb.ThumbSize).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).
|
||||
Where(
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Tag.Eq(req.TagName)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
storageInfoList, err := storageInfoQuery.Find()
|
||||
err = storageInfoQuery.Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -93,10 +105,16 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL
|
||||
|
||||
for _, dbFileInfo := range storageInfoList {
|
||||
wg.Add(1)
|
||||
go func(dbFileInfo *model.ScaStorageInfo) {
|
||||
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)
|
||||
@@ -109,15 +127,16 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL
|
||||
images = append(images, types.ImageMeta{
|
||||
ID: dbFileInfo.ID,
|
||||
FileName: dbFileInfo.FileName,
|
||||
Thumbnail: presignedUrl.String(),
|
||||
URL: url,
|
||||
Width: dbFileInfo.Width,
|
||||
Height: dbFileInfo.Height,
|
||||
Width: dbFileInfo.ThumbW,
|
||||
Height: dbFileInfo.ThumbH,
|
||||
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
groupedImages.Store(date, images)
|
||||
}(dbFileInfo)
|
||||
}(&dbFileInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
var imageList []types.AllImageDetail
|
||||
|
@@ -5,6 +5,7 @@ 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"
|
||||
@@ -38,12 +39,15 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque
|
||||
return nil, errors.New("user_id not found")
|
||||
}
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
storageInfos, err := storageInfo.Select(
|
||||
storageThumb := l.svcCtx.DB.ScaStorageThumb
|
||||
var thingList []types.ThingImageList
|
||||
err = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.Category,
|
||||
storageInfo.Tag,
|
||||
storageInfo.Path,
|
||||
storageThumb.ThumbPath,
|
||||
storageInfo.CreatedAt).
|
||||
LeftJoin(storageThumb, storageInfo.ThumbID.EqCol(storageThumb.ID)).
|
||||
Where(storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
@@ -52,28 +56,28 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque
|
||||
storageInfo.Category.Length().Gt(0),
|
||||
storageInfo.Tag.Length().Gte(0)).
|
||||
Order(storageInfo.CreatedAt.Desc()).
|
||||
Find()
|
||||
Scan(&thingList)
|
||||
if err != nil {
|
||||
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")
|
||||
}
|
||||
//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{}
|
||||
tagCoverMap := sync.Map{} // 用于存储每个 Tag 的封面图片路径
|
||||
|
||||
for _, info := range storageInfos {
|
||||
for _, info := range thingList {
|
||||
tagKey := info.Category + "::" + info.Tag
|
||||
if _, exists := tagCountMap.Load(tagKey); !exists {
|
||||
tagCountMap.Store(tagKey, int64(0))
|
||||
@@ -90,14 +94,15 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque
|
||||
// 为每个 Tag 存储封面图片路径
|
||||
if _, exists := tagCoverMap.Load(tagKey); !exists {
|
||||
// 使用服务生成预签名 URL
|
||||
coverImageURL, err := service.PresignedURL(l.ctx, req.Bucket, info.Path, 7*24*time.Hour)
|
||||
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, coverImageURL)
|
||||
tagCoverMap.Store(tagKey, presignedUrl.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var thingListData []types.ThingListData
|
||||
var thingListResponse []types.ThingListData
|
||||
categoryMap.Range(func(category, tagData interface{}) bool {
|
||||
var metas []types.ThingMeta
|
||||
tagData.(*sync.Map).Range(func(tag, item interface{}) bool {
|
||||
@@ -113,14 +118,14 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque
|
||||
metas = append(metas, meta)
|
||||
return true
|
||||
})
|
||||
thingListData = append(thingListData, types.ThingListData{
|
||||
thingListResponse = append(thingListResponse, types.ThingListData{
|
||||
Category: category.(string),
|
||||
List: metas,
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
return &types.ThingListResponse{Records: thingListData}, nil
|
||||
return &types.ThingListResponse{Records: thingListResponse}, nil
|
||||
}
|
||||
|
||||
// 提取解密操作为函数
|
||||
|
@@ -1,17 +1,23 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"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"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"schisandra-album-cloud-microservices/app/aisvc/rpc/pb"
|
||||
@@ -56,72 +62,159 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
defer func(file multipart.File) {
|
||||
_ = file.Close()
|
||||
}(file)
|
||||
|
||||
// 解析 AI 识别结果
|
||||
result, err := l.parseAIRecognitionResult(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var faceId int64 = 0
|
||||
bytes, err := io.ReadAll(file)
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 人脸识别
|
||||
if result.FileType == "image/png" || result.FileType == "image/jpeg" {
|
||||
face, err := l.svcCtx.AiSvcRpc.FaceRecognition(l.ctx, &pb.FaceRecognitionRequest{Face: bytes, UserId: uid})
|
||||
if err != nil {
|
||||
return "", err
|
||||
// 解析上传的缩略图
|
||||
thumbnail, _, err := l.getUploadedThumbnail(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer thumbnail.Close()
|
||||
|
||||
// 解析图片信息识别结果
|
||||
result, err := l.parseImageInfoResult(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 使用 `errgroup.Group` 处理并发任务
|
||||
var (
|
||||
faceId int64
|
||||
filePath string
|
||||
minioFilePath string
|
||||
presignedURL string
|
||||
)
|
||||
g, ctx := errgroup.WithContext(context.Background())
|
||||
// 创建信号量,限制最大并发上传数(比如最多同时 5 个任务)
|
||||
sem := semaphore.NewWeighted(5)
|
||||
|
||||
// 进行人脸识别
|
||||
g.Go(func() error {
|
||||
if result.FileType == "image/png" || result.FileType == "image/jpeg" {
|
||||
face, err := l.svcCtx.AiSvcRpc.FaceRecognition(l.ctx, &pb.FaceRecognitionRequest{
|
||||
Face: data,
|
||||
UserId: uid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if face != nil {
|
||||
faceId = face.GetFaceId()
|
||||
}
|
||||
}
|
||||
if face != nil {
|
||||
faceId = face.GetFaceId()
|
||||
}
|
||||
}
|
||||
|
||||
// 根据 GPS 信息获取地理位置信息
|
||||
country, province, city, err := l.getGeoLocation(result.Latitude, result.Longitude)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
// 上传文件到 OSS
|
||||
// 重新设置文件指针到文件开头
|
||||
if _, err = file.Seek(0, 0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
bucket, provider, filePath, url, err := l.uploadFileToOSS(uid, header, file, result)
|
||||
if err != nil {
|
||||
g.Go(func() error {
|
||||
if err := sem.Acquire(ctx, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
defer sem.Release(1)
|
||||
|
||||
// 重新创建 `multipart.File` 兼容的 `Reader`
|
||||
fileReader := struct {
|
||||
*bytes.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: bytes.NewReader(data),
|
||||
Closer: io.NopCloser(nil),
|
||||
}
|
||||
|
||||
fileUrl, err := l.uploadFileToOSS(uid, header, fileReader, 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, url, err := l.uploadFileToMinio(uid, header, thumbnail, result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
minioFilePath = path
|
||||
presignedURL = url
|
||||
return nil
|
||||
})
|
||||
|
||||
// 等待所有 goroutine 执行完毕
|
||||
if err = g.Wait(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 将地址信息保存到数据库
|
||||
locationId, err := l.saveFileLocationInfoToDB(uid, result.Provider, result.Bucket, result.Latitude, result.Longitude, country, province, city, filePath)
|
||||
fileUploadMessage := &types.FileUploadMessage{
|
||||
UID: uid,
|
||||
Data: result,
|
||||
FaceID: faceId,
|
||||
FileHeader: header,
|
||||
FilePath: filePath,
|
||||
PresignedURL: presignedURL,
|
||||
ThumbPath: minioFilePath,
|
||||
}
|
||||
// 转换为 JSON
|
||||
messageData, err := json.Marshal(fileUploadMessage)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = l.svcCtx.NSQProducer.Publish(constant.MQTopicImageProcess, messageData)
|
||||
if err != nil {
|
||||
return "", errors.New("publish message failed")
|
||||
}
|
||||
|
||||
// 将 EXIF 和文件信息存入数据库
|
||||
id, err := l.saveFileInfoToDB(uid, bucket, provider, header, result, locationId, faceId, filePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 删除缓存
|
||||
l.afterImageUpload(uid, provider, bucket)
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// redis 保存最近7天上传的文件列表
|
||||
err = l.saveRecentFileList(uid, url, id, result, header.Filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//// 根据 GPS 信息获取地理位置信息
|
||||
//country, province, city, err := l.getGeoLocation(result.Latitude, result.Longitude)
|
||||
//if err != nil {
|
||||
// return "", err
|
||||
//}
|
||||
//// 将地址信息保存到数据库
|
||||
//locationId, err := l.saveFileLocationInfoToDB(uid, result.Provider, result.Bucket, result.Latitude, result.Longitude, country, province, city, filePath)
|
||||
//if err != nil {
|
||||
// return "", err
|
||||
//}
|
||||
//
|
||||
//// 将 EXIF 和文件信息存入数据库
|
||||
//id, err := l.saveFileInfoToDB(uid, bucket, provider, header, result, locationId, faceId, filePath)
|
||||
//if err != nil {
|
||||
// return "", err
|
||||
//}
|
||||
//// 删除缓存
|
||||
//l.afterImageUpload(uid, provider, bucket)
|
||||
//
|
||||
//// redis 保存最近7天上传的文件列表
|
||||
//err = l.saveRecentFileList(uid, url, id, result, header.Filename)
|
||||
//if err != nil {
|
||||
// return "", err
|
||||
//}
|
||||
|
||||
return "success", nil
|
||||
}
|
||||
|
||||
// 将 multipart.File 转为 Base64 字符串
|
||||
func (l *UploadFileLogic) fileToBase64(file multipart.File) (string, error) {
|
||||
// 读取文件内容
|
||||
fileBytes, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 将文件内容转为 Base64 编码
|
||||
return base64.StdEncoding.EncodeToString(fileBytes), nil
|
||||
}
|
||||
|
||||
// 获取用户 ID
|
||||
func (l *UploadFileLogic) getUserID() (string, error) {
|
||||
uid, ok := l.ctx.Value("user_id").(string)
|
||||
@@ -150,8 +243,17 @@ func (l *UploadFileLogic) getUploadedFile(r *http.Request) (multipart.File, *mul
|
||||
return file, header, nil
|
||||
}
|
||||
|
||||
// 解析 AI 识别结果
|
||||
func (l *UploadFileLogic) parseAIRecognitionResult(r *http.Request) (types.File, error) {
|
||||
// 解析上传的文件
|
||||
func (l *UploadFileLogic) getUploadedThumbnail(r *http.Request) (multipart.File, *multipart.FileHeader, error) {
|
||||
file, header, err := r.FormFile("thumbnail")
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("file not found")
|
||||
}
|
||||
return file, header, nil
|
||||
}
|
||||
|
||||
// 解析图片信息结果
|
||||
func (l *UploadFileLogic) parseImageInfoResult(r *http.Request) (types.File, error) {
|
||||
formValue := r.PostFormValue("data")
|
||||
var result types.File
|
||||
if err := json.Unmarshal([]byte(formValue), &result); err != nil {
|
||||
@@ -160,47 +262,11 @@ func (l *UploadFileLogic) parseAIRecognitionResult(r *http.Request) (types.File,
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 提取拍摄时间
|
||||
func (l *UploadFileLogic) extractOriginalDateTime(exif map[string]interface{}) (string, error) {
|
||||
if dateTimeOriginal, ok := exif["DateTimeOriginal"].(string); ok {
|
||||
parsedTime, err := time.Parse(time.RFC3339, dateTimeOriginal)
|
||||
if err == nil {
|
||||
return parsedTime.Format("2006-01-02 15:04:05"), nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// 根据 GPS 信息获取地理位置信息
|
||||
func (l *UploadFileLogic) getGeoLocation(latitude, longitude float64) (string, string, string, error) {
|
||||
if latitude == 0.000000 || longitude == 0.000000 {
|
||||
return "", "", "", nil
|
||||
}
|
||||
|
||||
//request := gao_map.ReGeoRequest{Location: fmt.Sprintf("%f,%f", latitude, longitude)}
|
||||
//
|
||||
//location, err := l.svcCtx.GaoMap.Location.ReGeo(&request)
|
||||
//if err != nil {
|
||||
// return nil, errors.New("regeo failed")
|
||||
//}
|
||||
//
|
||||
//addressInfo := map[string]string{}
|
||||
//if location.ReGeoCode.AddressComponent.Country != "" {
|
||||
// addressInfo["country"] = location.ReGeoCode.AddressComponent.Country
|
||||
//}
|
||||
//if location.ReGeoCode.AddressComponent.Province != "" {
|
||||
// addressInfo["province"] = location.ReGeoCode.AddressComponent.Province
|
||||
//}
|
||||
//if location.ReGeoCode.AddressComponent.City != "" {
|
||||
// addressInfo["city"] = location.ReGeoCode.AddressComponent.City.(string)
|
||||
//}
|
||||
//if location.ReGeoCode.AddressComponent.District != "" {
|
||||
// addressInfo["district"] = location.ReGeoCode.AddressComponent.District.(string)
|
||||
//}
|
||||
//if location.ReGeoCode.AddressComponent.Township != "" {
|
||||
// addressInfo["township"] = location.ReGeoCode.AddressComponent.Township
|
||||
//}
|
||||
|
||||
country, province, city, err := geo_json.GetAddress(latitude, longitude, l.svcCtx.GeoRegionData)
|
||||
if err != nil {
|
||||
return "", "", "", errors.New("get geo location failed")
|
||||
@@ -210,20 +276,21 @@ func (l *UploadFileLogic) getGeoLocation(latitude, longitude float64) (string, s
|
||||
}
|
||||
|
||||
// 上传文件到 OSS
|
||||
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, string, string, string, error) {
|
||||
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (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(
|
||||
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)),
|
||||
)
|
||||
|
||||
@@ -231,13 +298,50 @@ 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)
|
||||
//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, 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 "", "", "", "", errors.New("presigned url failed")
|
||||
return "", "", err
|
||||
}
|
||||
return ossConfig.BucketName, ossConfig.Provider, objectKey, url, nil
|
||||
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, presignedURL.String(), nil
|
||||
}
|
||||
|
||||
func (l *UploadFileLogic) saveFileLocationInfoToDB(uid string, provider string, bucket string, latitude float64, longitude float64, country string, province string, city string, filePath string) (int64, error) {
|
||||
|
305
app/auth/api/internal/mq/image_process_consumer.go
Normal file
305
app/auth/api/internal/mq/image_process_consumer.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package mq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/nsqio/go-nsq"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"gorm.io/gorm"
|
||||
"mime/multipart"
|
||||
"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"
|
||||
"schisandra-album-cloud-microservices/common/geo_json"
|
||||
"schisandra-album-cloud-microservices/common/nsqx"
|
||||
"schisandra-album-cloud-microservices/common/storage/config"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NsqImageProcessConsumer struct {
|
||||
svcCtx *svc.ServiceContext
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func NewImageProcessConsumer(svcCtx *svc.ServiceContext) {
|
||||
consumer := nsqx.NewNSQConsumer(constant.MQTopicImageProcess)
|
||||
consumer.AddHandler(&NsqImageProcessConsumer{
|
||||
svcCtx: svcCtx,
|
||||
ctx: context.Background(),
|
||||
})
|
||||
err := consumer.ConnectToNSQD(svcCtx.Config.NSQ.NSQDHost)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *NsqImageProcessConsumer) HandleMessage(msg *nsq.Message) error {
|
||||
if len(msg.Body) == 0 {
|
||||
return errors.New("empty message body")
|
||||
}
|
||||
var message types.FileUploadMessage
|
||||
err := json.Unmarshal(msg.Body, &message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 根据 GPS 信息获取地理位置信息
|
||||
country, province, city, err := c.getGeoLocation(message.Data.Latitude, message.Data.Longitude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 将地址信息保存到数据库
|
||||
locationId, err := c.saveFileLocationInfoToDB(message.UID, message.Data.Provider, message.Data.Bucket, message.Data.Latitude, message.Data.Longitude, country, province, city, message.ThumbPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
thumbnailId, err := c.saveFileThumbnailInfoToDB(message.UID, message.ThumbPath, message.Data.ThumbW, message.Data.ThumbH, message.Data.ThumbSize)
|
||||
|
||||
// 将文件信息存入数据库
|
||||
id, err := c.saveFileInfoToDB(message.UID, message.Data.Bucket, message.Data.Provider, message.FileHeader, message.Data, locationId, message.FaceID, message.FilePath, thumbnailId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 删除缓存
|
||||
c.afterImageUpload(message.UID, message.Data.Provider, message.Data.Bucket)
|
||||
|
||||
// redis 保存最近7天上传的文件列表
|
||||
err = c.saveRecentFileList(message.UID, message.PresignedURL, id, message.Data, message.FileHeader.Filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据 GPS 信息获取地理位置信息
|
||||
func (c *NsqImageProcessConsumer) getGeoLocation(latitude, longitude float64) (string, string, string, error) {
|
||||
if latitude == 0.000000 || longitude == 0.000000 {
|
||||
return "", "", "", nil
|
||||
}
|
||||
country, province, city, err := geo_json.GetAddress(latitude, longitude, c.svcCtx.GeoRegionData)
|
||||
if err != nil {
|
||||
return "", "", "", errors.New("get geo location failed")
|
||||
}
|
||||
|
||||
return country, province, city, nil
|
||||
}
|
||||
|
||||
// 从缓存或数据库中获取 OSS 配置
|
||||
func (c *NsqImageProcessConsumer) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*config.StorageConfig, error) {
|
||||
result, err := c.svcCtx.RedisClient.Get(c.ctx, cacheKey).Result()
|
||||
if err != nil && !errors.Is(err, redis.Nil) {
|
||||
return nil, errors.New("get oss config failed")
|
||||
}
|
||||
|
||||
var ossConfig *config.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 c.decryptConfig(&redisOssConfig)
|
||||
}
|
||||
|
||||
// 缓存未命中,从数据库中加载
|
||||
scaOssConfig := c.svcCtx.DB.ScaStorageConfig
|
||||
dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 缓存数据库配置
|
||||
ossConfig, err = c.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 = c.svcCtx.RedisClient.Set(c.ctx, cacheKey, marshalData, 0).Err()
|
||||
if err != nil {
|
||||
return nil, errors.New("set oss config failed")
|
||||
}
|
||||
|
||||
return ossConfig, nil
|
||||
}
|
||||
|
||||
func (c *NsqImageProcessConsumer) classifyFile(mimeType string, isScreenshot bool) string {
|
||||
// 使用map存储MIME类型及其对应的分类
|
||||
typeMap := map[string]string{
|
||||
"image/jpeg": "image",
|
||||
"image/png": "image",
|
||||
"image/gif": "gif",
|
||||
"image/bmp": "image",
|
||||
"image/tiff": "image",
|
||||
"image/webp": "image",
|
||||
"video/mp4": "video",
|
||||
"video/avi": "video",
|
||||
"video/mpeg": "video",
|
||||
"video/quicktime": "video",
|
||||
"video/x-msvideo": "video",
|
||||
"video/x-flv": "video",
|
||||
"video/x-matroska": "video",
|
||||
}
|
||||
|
||||
// 根据MIME类型从map中获取分类
|
||||
if classification, exists := typeMap[mimeType]; exists {
|
||||
return classification
|
||||
}
|
||||
|
||||
// 如果isScreenshot为true,则返回"screenshot"
|
||||
if isScreenshot {
|
||||
return "screenshot"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// 保存最近7天上传的文件列表
|
||||
func (c *NsqImageProcessConsumer) saveRecentFileList(uid, 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.Width,
|
||||
Height: result.Height,
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, errors.New("decrypt access key failed")
|
||||
}
|
||||
secretKey, err := encrypt.Decrypt(dbConfig.SecretKey, c.svcCtx.Config.Encrypt.Key)
|
||||
if err != nil {
|
||||
return nil, errors.New("decrypt secret key failed")
|
||||
}
|
||||
return &config.StorageConfig{
|
||||
Provider: dbConfig.Provider,
|
||||
Endpoint: dbConfig.Endpoint,
|
||||
AccessKey: accessKey,
|
||||
SecretKey: secretKey,
|
||||
BucketName: dbConfig.Bucket,
|
||||
Region: dbConfig.Region,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *NsqImageProcessConsumer) saveFileLocationInfoToDB(uid string, provider string, bucket string, latitude float64, longitude float64, country string, province string, city string, filePath string) (int64, error) {
|
||||
if latitude == 0.000000 || longitude == 0.000000 {
|
||||
return 0, nil
|
||||
}
|
||||
locationDB := c.svcCtx.DB.ScaStorageLocation
|
||||
storageLocations, err := locationDB.Where(locationDB.UserID.Eq(uid), locationDB.Province.Eq(province), locationDB.City.Eq(city)).First()
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return 0, err
|
||||
}
|
||||
if storageLocations == nil {
|
||||
locationInfo := model.ScaStorageLocation{
|
||||
Provider: provider,
|
||||
Bucket: bucket,
|
||||
UserID: uid,
|
||||
Country: country,
|
||||
City: city,
|
||||
Province: province,
|
||||
Latitude: fmt.Sprintf("%f", latitude),
|
||||
Longitude: fmt.Sprintf("%f", longitude),
|
||||
Total: 1,
|
||||
CoverImage: filePath,
|
||||
}
|
||||
err = locationDB.Create(&locationInfo)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return locationInfo.ID, nil
|
||||
} else {
|
||||
info, err := locationDB.Where(locationDB.ID.Eq(storageLocations.ID), locationDB.UserID.Eq(uid)).UpdateColumnSimple(locationDB.Total.Add(1), locationDB.CoverImage.Value(filePath))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if info.RowsAffected == 0 {
|
||||
return 0, errors.New("update location failed")
|
||||
}
|
||||
return storageLocations.ID, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *NsqImageProcessConsumer) saveFileThumbnailInfoToDB(uid string, filePath string, width, height float64, size float64) (int64, error) {
|
||||
storageThumb := c.svcCtx.DB.ScaStorageThumb
|
||||
storageThumbInfo := &model.ScaStorageThumb{
|
||||
UserID: uid,
|
||||
ThumbPath: filePath,
|
||||
ThumbW: width,
|
||||
ThumbH: height,
|
||||
ThumbSize: size,
|
||||
}
|
||||
err := storageThumb.Create(storageThumbInfo)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return 0, errors.New("create storage thumb failed")
|
||||
}
|
||||
return storageThumbInfo.ID, nil
|
||||
}
|
||||
|
||||
// 将 EXIF 和文件信息存入数据库
|
||||
func (c *NsqImageProcessConsumer) saveFileInfoToDB(uid, bucket, provider string, header *multipart.FileHeader, result types.File, locationId, faceId int64, filePath string, thumbnailId int64) (int64, error) {
|
||||
|
||||
typeName := c.classifyFile(result.FileType, result.IsScreenshot)
|
||||
scaStorageInfo := &model.ScaStorageInfo{
|
||||
UserID: uid,
|
||||
Provider: provider,
|
||||
Bucket: bucket,
|
||||
FileName: header.Filename,
|
||||
FileSize: strconv.FormatInt(header.Size, 10),
|
||||
FileType: result.FileType,
|
||||
Path: filePath,
|
||||
Landscape: result.Landscape,
|
||||
Tag: result.TagName,
|
||||
IsAnime: strconv.FormatBool(result.IsAnime),
|
||||
Category: result.TopCategory,
|
||||
LocationID: locationId,
|
||||
FaceID: faceId,
|
||||
Type: typeName,
|
||||
Width: result.Width,
|
||||
Height: result.Height,
|
||||
ThumbID: thumbnailId,
|
||||
}
|
||||
|
||||
err := c.svcCtx.DB.ScaStorageInfo.Create(scaStorageInfo)
|
||||
if err != nil {
|
||||
return 0, errors.New("create storage info failed")
|
||||
}
|
||||
return scaStorageInfo.ID, nil
|
||||
}
|
||||
|
||||
// 在UploadImageLogic或其他需要使缓存失效的逻辑中添加:
|
||||
func (c *NsqImageProcessConsumer) afterImageUpload(uid, provider, bucket string) {
|
||||
for _, sort := range []bool{true, false} {
|
||||
key := fmt.Sprintf("%s%s:%s:%s:%v", constant.ImageListPrefix, uid, provider, bucket, sort)
|
||||
if err := c.svcCtx.RedisClient.Del(c.ctx, key).Err(); err != nil {
|
||||
logx.Errorf("删除缓存键 %s 失败: %v", key, err)
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/nsqio/go-nsq"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/wenlng/go-captcha/v2/rotate"
|
||||
"github.com/wenlng/go-captcha/v2/slide"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
"schisandra-album-cloud-microservices/common/geo_json"
|
||||
"schisandra-album-cloud-microservices/common/ip2region"
|
||||
"schisandra-album-cloud-microservices/common/miniox"
|
||||
"schisandra-album-cloud-microservices/common/nsqx"
|
||||
"schisandra-album-cloud-microservices/common/redisx"
|
||||
"schisandra-album-cloud-microservices/common/sensitivex"
|
||||
"schisandra-album-cloud-microservices/common/storage"
|
||||
@@ -45,13 +47,14 @@ type ServiceContext struct {
|
||||
StorageManager *manager.Manager
|
||||
MinioClient *minio.Client
|
||||
GeoRegionData *geo_json.RegionData
|
||||
NSQProducer *nsq.Producer
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
redisClient := redisx.NewRedis(c.Redis.Host, c.Redis.Pass, c.Redis.DB)
|
||||
db, queryDB := mysql.NewMySQL(c.Mysql.DataSource, c.Mysql.MaxOpenConn, c.Mysql.MaxIdleConn, redisClient)
|
||||
casbinEnforcer := casbinx.NewCasbin(db)
|
||||
return &ServiceContext{
|
||||
serviceContext := &ServiceContext{
|
||||
Config: c,
|
||||
SecurityHeadersMiddleware: middleware.NewSecurityHeadersMiddleware().Handle,
|
||||
CasbinVerifyMiddleware: middleware.NewCasbinVerifyMiddleware(casbinEnforcer).Handle,
|
||||
@@ -68,5 +71,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
AiSvcRpc: aiservice.NewAiService(zrpc.MustNewClient(c.AiSvcRpc)),
|
||||
MinioClient: miniox.NewMinio(c.Minio.Endpoint, c.Minio.AccessKeyID, c.Minio.SecretAccessKey, c.Minio.UseSSL),
|
||||
GeoRegionData: geo_json.NewGeoJSON(),
|
||||
NSQProducer: nsqx.NewNsqProducer(c.NSQ.NSQDHost),
|
||||
}
|
||||
return serviceContext
|
||||
}
|
||||
|
@@ -1,17 +0,0 @@
|
||||
package types
|
||||
|
||||
// File represents a file uploaded by the user.
|
||||
type File struct {
|
||||
Provider string `json:"provider"`
|
||||
Bucket string `json:"bucket"`
|
||||
FileType string `json:"fileType"`
|
||||
IsAnime bool `json:"isAnime"`
|
||||
TagName string `json:"tagName"`
|
||||
Landscape string `json:"landscape"`
|
||||
TopCategory string `json:"topCategory"`
|
||||
IsScreenshot bool `json:"isScreenshot"`
|
||||
Width float64 `json:"width"`
|
||||
Height float64 `json:"height"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
}
|
56
app/auth/api/internal/types/file_types.go
Normal file
56
app/auth/api/internal/types/file_types.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
"time"
|
||||
)
|
||||
|
||||
// File represents a file uploaded by the user.
|
||||
type File struct {
|
||||
Provider string `json:"provider"`
|
||||
Bucket string `json:"bucket"`
|
||||
FileType string `json:"fileType"`
|
||||
IsAnime bool `json:"isAnime"`
|
||||
TagName string `json:"tagName"`
|
||||
Landscape string `json:"landscape"`
|
||||
TopCategory string `json:"topCategory"`
|
||||
IsScreenshot bool `json:"isScreenshot"`
|
||||
Width float64 `json:"width"`
|
||||
Height float64 `json:"height"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
ThumbW float64 `json:"thumb_w"`
|
||||
ThumbH float64 `json:"thumb_h"`
|
||||
ThumbSize float64 `json:"thumb_size"`
|
||||
}
|
||||
|
||||
// FileUploadMessage represents a message sent to the user after a file upload.
|
||||
type FileUploadMessage struct {
|
||||
FaceID int64 `json:"face_id"`
|
||||
FileHeader *multipart.FileHeader `json:"fileHeader"`
|
||||
Data File `json:"data"`
|
||||
UID string `json:"uid"`
|
||||
FilePath string `json:"filePath"`
|
||||
PresignedURL string `json:"presignedURL"`
|
||||
ThumbPath string `json:"thumbPath"`
|
||||
}
|
||||
|
||||
type FileInfoResult struct {
|
||||
ID int64 `json:"id"`
|
||||
FileName string `json:"file_name"`
|
||||
ThumbPath string `json:"thumb_path"`
|
||||
ThumbW float64 `json:"thumb_w"`
|
||||
ThumbH float64 `json:"thumb_h"`
|
||||
ThumbSize float64 `json:"thumb_size"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type ThingImageList struct {
|
||||
ID int64 `json:"id"`
|
||||
Category string `json:"category"`
|
||||
Tag string `json:"tag"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ThumbPath string `json:"thumb_path"`
|
||||
Path string `json:"path"`
|
||||
}
|
@@ -178,6 +178,7 @@ type ImageMeta struct {
|
||||
Width float64 `json:"width"`
|
||||
Height float64 `json:"height"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
}
|
||||
|
||||
type LocationDetailListRequest struct {
|
||||
@@ -305,6 +306,10 @@ type RotateCaptchaResponse struct {
|
||||
Thumb string `json:"thumb"`
|
||||
}
|
||||
|
||||
type SingleImageRequest struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type SlideCaptchaResponse struct {
|
||||
Key string `json:"key"`
|
||||
Image string `json:"image"`
|
||||
|
@@ -117,6 +117,7 @@ func main() {
|
||||
scaUserMessage := g.GenerateModel("sca_user_message", fieldOpts...)
|
||||
scaStorageAlbum := g.GenerateModel("sca_storage_album", fieldOpts...)
|
||||
scaStorageLocation := g.GenerateModel("sca_storage_location", fieldOpts...)
|
||||
scaStorageThumb := g.GenerateModel("sca_storage_thumb", fieldOpts...)
|
||||
|
||||
g.ApplyBasic(
|
||||
scaAuthMenu,
|
||||
@@ -137,6 +138,7 @@ func main() {
|
||||
scaUserMessage,
|
||||
scaStorageAlbum,
|
||||
scaStorageLocation,
|
||||
scaStorageThumb,
|
||||
)
|
||||
|
||||
g.Execute()
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaAuthMenu = "sca_auth_menu"
|
||||
|
||||
// ScaAuthMenu mapped from table <sca_auth_menu>
|
||||
// ScaAuthMenu 菜单表
|
||||
type ScaAuthMenu struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键ID;primary_key" json:"id,string"` // 主键ID
|
||||
MenuName string `gorm:"column:menu_name;type:varchar(64);comment:名称" json:"menu_name"` // 名称
|
||||
|
@@ -6,7 +6,7 @@ package model
|
||||
|
||||
const TableNameScaAuthPermissionRule = "sca_auth_permission_rule"
|
||||
|
||||
// ScaAuthPermissionRule mapped from table <sca_auth_permission_rule>
|
||||
// ScaAuthPermissionRule 接口权限表
|
||||
type ScaAuthPermissionRule struct {
|
||||
ID int64 `gorm:"column:id;type:int(11);primaryKey;autoIncrement:true;primary_key" json:"id,string"`
|
||||
Ptype string `gorm:"column:ptype;type:varchar(100);uniqueIndex:idx_sca_auth_permission_rule,priority:1;index:IDX_sca_auth_permission_rule_ptype,priority:1" json:"ptype"`
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaAuthRole = "sca_auth_role"
|
||||
|
||||
// ScaAuthRole mapped from table <sca_auth_role>
|
||||
// ScaAuthRole 角色表
|
||||
type ScaAuthRole struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键ID;primary_key" json:"id,string"` // 主键ID
|
||||
RoleName string `gorm:"column:role_name;type:varchar(32);not null;comment:角色名称" json:"role_name"` // 角色名称
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaAuthUser = "sca_auth_user"
|
||||
|
||||
// ScaAuthUser mapped from table <sca_auth_user>
|
||||
// ScaAuthUser 用户表
|
||||
type ScaAuthUser struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;uniqueIndex:id,priority:1;comment:自增ID;primary_key" json:"id,string"` // 自增ID
|
||||
UID string `gorm:"column:uid;type:varchar(50);not null;uniqueIndex:uid,priority:1;comment:唯一ID" json:"uid"` // 唯一ID
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaAuthUserDevice = "sca_auth_user_device"
|
||||
|
||||
// ScaAuthUserDevice mapped from table <sca_auth_user_device>
|
||||
// ScaAuthUserDevice 用户设备表
|
||||
type ScaAuthUserDevice struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键ID;primary_key" json:"id,string"` // 主键ID
|
||||
UserID string `gorm:"column:user_id;type:varchar(20);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaAuthUserSocial = "sca_auth_user_social"
|
||||
|
||||
// ScaAuthUserSocial mapped from table <sca_auth_user_social>
|
||||
// ScaAuthUserSocial 第三方登录信息表
|
||||
type ScaAuthUserSocial struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键ID;primary_key" json:"id,string"` // 主键ID
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
const TableNameScaCommentLike = "sca_comment_likes"
|
||||
|
||||
// ScaCommentLike mapped from table <sca_comment_likes>
|
||||
// ScaCommentLike 评论点赞表
|
||||
type ScaCommentLike struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键id;primary_key" json:"id,string"` // 主键id
|
||||
TopicID string `gorm:"column:topic_id;type:varchar(50);not null;comment:话题ID" json:"topic_id"` // 话题ID
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
const TableNameScaCommentReply = "sca_comment_reply"
|
||||
|
||||
// ScaCommentReply mapped from table <sca_comment_reply>
|
||||
// ScaCommentReply 评论表
|
||||
type ScaCommentReply struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;uniqueIndex:id,priority:1;comment:主键id;primary_key" json:"id,string"` // 主键id
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);not null;comment:评论用户id" json:"user_id"` // 评论用户id
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaMessageReport = "sca_message_report"
|
||||
|
||||
// ScaMessageReport mapped from table <sca_message_report>
|
||||
// ScaMessageReport 评论举报表
|
||||
type ScaMessageReport struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(20);comment:用户Id" json:"user_id"` // 用户Id
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaStorageAlbum = "sca_storage_album"
|
||||
|
||||
// ScaStorageAlbum mapped from table <sca_storage_album>
|
||||
// ScaStorageAlbum 相册信息表
|
||||
type ScaStorageAlbum struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);comment:用户ID" json:"user_id"` // 用户ID
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaStorageConfig = "sca_storage_config"
|
||||
|
||||
// ScaStorageConfig mapped from table <sca_storage_config>
|
||||
// ScaStorageConfig 用户存储配置表
|
||||
type ScaStorageConfig struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaStorageInfo = "sca_storage_info"
|
||||
|
||||
// ScaStorageInfo mapped from table <sca_storage_info>
|
||||
// ScaStorageInfo 文件存储信息表
|
||||
type ScaStorageInfo struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
@@ -24,6 +24,7 @@ type ScaStorageInfo struct {
|
||||
FileType string `gorm:"column:file_type;type:varchar(50);comment:文件类型" json:"file_type"` // 文件类型
|
||||
Width float64 `gorm:"column:width;type:double;comment:宽" json:"width"` // 宽
|
||||
Height float64 `gorm:"column:height;type:double;comment:高" json:"height"` // 高
|
||||
ThumbID int64 `gorm:"column:thumb_id;type:bigint(20);comment:缩略图id" json:"thumb_id"` // 缩略图id
|
||||
Category string `gorm:"column:category;type:varchar(50);comment:分类" json:"category"` // 分类
|
||||
Tag string `gorm:"column:tag;type:varchar(255);comment:标签" json:"tag"` // 标签
|
||||
Type string `gorm:"column:type;type:varchar(50);comment:类型" json:"type"` // 类型
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
const TableNameScaStorageLocation = "sca_storage_location"
|
||||
|
||||
// ScaStorageLocation mapped from table <sca_storage_location>
|
||||
// ScaStorageLocation 文件地理位置信息表
|
||||
type ScaStorageLocation struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);comment:用户id" json:"user_id"` // 用户id
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaStorageTag = "sca_storage_tag"
|
||||
|
||||
// ScaStorageTag mapped from table <sca_storage_tag>
|
||||
// ScaStorageTag 标签表
|
||||
type ScaStorageTag struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
FileID int64 `gorm:"column:file_id;type:bigint(20);comment:文件ID" json:"file_id"` // 文件ID
|
||||
|
31
app/auth/model/mysql/model/sca_storage_thumb.gen.go
Normal file
31
app/auth/model/mysql/model/sca_storage_thumb.gen.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const TableNameScaStorageThumb = "sca_storage_thumb"
|
||||
|
||||
// ScaStorageThumb mapped from table <sca_storage_thumb>
|
||||
type ScaStorageThumb struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
ThumbPath string `gorm:"column:thumb_path;type:text;comment:缩略图路径" json:"thumb_path"` // 缩略图路径
|
||||
ThumbW float64 `gorm:"column:thumb_w;type:double;comment:缩略图宽" json:"thumb_w"` // 缩略图宽
|
||||
ThumbH float64 `gorm:"column:thumb_h;type:double;comment:缩略图高" json:"thumb_h"` // 缩略图高
|
||||
ThumbSize float64 `gorm:"column:thumb_size;type:double;comment:缩略图大小" json:"thumb_size"` // 缩略图大小
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:timestamp;autoCreateTime;comment:创建时间" json:"created_at"` // 创建时间
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp;autoUpdateTime;comment:更新时间" json:"updated_at"` // 更新时间
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp;comment:删除时间" json:"deleted_at"` // 删除时间
|
||||
}
|
||||
|
||||
// TableName ScaStorageThumb's table name
|
||||
func (*ScaStorageThumb) TableName() string {
|
||||
return TableNameScaStorageThumb
|
||||
}
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaUserFollow = "sca_user_follows"
|
||||
|
||||
// ScaUserFollow mapped from table <sca_user_follows>
|
||||
// ScaUserFollow 用户关注表
|
||||
type ScaUserFollow struct {
|
||||
FollowerID string `gorm:"column:follower_id;type:varchar(50);not null;comment:关注者" json:"follower_id"` // 关注者
|
||||
FolloweeID string `gorm:"column:followee_id;type:varchar(50);not null;comment:被关注者" json:"followee_id"` // 被关注者
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaUserLevel = "sca_user_level"
|
||||
|
||||
// ScaUserLevel mapped from table <sca_user_level>
|
||||
// ScaUserLevel 用户等级表
|
||||
type ScaUserLevel struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
UserID string `gorm:"column:user_id;type:varchar(50);comment:用户Id" json:"user_id"` // 用户Id
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
const TableNameScaUserMessage = "sca_user_message"
|
||||
|
||||
// ScaUserMessage mapped from table <sca_user_message>
|
||||
// ScaUserMessage 用户消息表
|
||||
type ScaUserMessage struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;autoIncrement:true;comment:主键;primary_key" json:"id,string"` // 主键
|
||||
TopicID string `gorm:"column:topic_id;type:varchar(50);comment:话题Id" json:"topic_id"` // 话题Id
|
||||
|
@@ -23,11 +23,11 @@ func NewMySQL(url string, maxOpenConn int, maxIdleConn int, client *redis.Client
|
||||
Logger: logger.New(
|
||||
log.New(os.Stdout, "\r\n", log.LstdFlags),
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // 慢sql日志
|
||||
LogLevel: logger.Error, // 级别
|
||||
Colorful: true, // 颜色
|
||||
IgnoreRecordNotFoundError: true, // 忽略RecordNotFoundError
|
||||
ParameterizedQueries: true, // 格式化SQL语句
|
||||
SlowThreshold: time.Second, // 慢sql日志
|
||||
LogLevel: logger.Info, // 级别
|
||||
Colorful: true, // 颜色
|
||||
IgnoreRecordNotFoundError: true, // 忽略RecordNotFoundError
|
||||
ParameterizedQueries: true, // 格式化SQL语句
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
@@ -41,7 +41,7 @@ func NewMySQL(url string, maxOpenConn int, maxIdleConn int, client *redis.Client
|
||||
sqlDB.SetMaxIdleConns(maxIdleConn)
|
||||
useDB := query.Use(db)
|
||||
// migrate
|
||||
Migrate(db)
|
||||
//Migrate(db)
|
||||
// cache
|
||||
gormCache, err := cache.NewGorm2Cache(&config.CacheConfig{
|
||||
CacheLevel: config.CacheLevelAll,
|
||||
|
@@ -32,6 +32,7 @@ var (
|
||||
ScaStorageLocation *scaStorageLocation
|
||||
ScaStorageTag *scaStorageTag
|
||||
ScaStorageTagInfo *scaStorageTagInfo
|
||||
ScaStorageThumb *scaStorageThumb
|
||||
ScaUserFollow *scaUserFollow
|
||||
ScaUserLevel *scaUserLevel
|
||||
ScaUserMessage *scaUserMessage
|
||||
@@ -54,6 +55,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
||||
ScaStorageLocation = &Q.ScaStorageLocation
|
||||
ScaStorageTag = &Q.ScaStorageTag
|
||||
ScaStorageTagInfo = &Q.ScaStorageTagInfo
|
||||
ScaStorageThumb = &Q.ScaStorageThumb
|
||||
ScaUserFollow = &Q.ScaUserFollow
|
||||
ScaUserLevel = &Q.ScaUserLevel
|
||||
ScaUserMessage = &Q.ScaUserMessage
|
||||
@@ -77,6 +79,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
|
||||
ScaStorageLocation: newScaStorageLocation(db, opts...),
|
||||
ScaStorageTag: newScaStorageTag(db, opts...),
|
||||
ScaStorageTagInfo: newScaStorageTagInfo(db, opts...),
|
||||
ScaStorageThumb: newScaStorageThumb(db, opts...),
|
||||
ScaUserFollow: newScaUserFollow(db, opts...),
|
||||
ScaUserLevel: newScaUserLevel(db, opts...),
|
||||
ScaUserMessage: newScaUserMessage(db, opts...),
|
||||
@@ -101,6 +104,7 @@ type Query struct {
|
||||
ScaStorageLocation scaStorageLocation
|
||||
ScaStorageTag scaStorageTag
|
||||
ScaStorageTagInfo scaStorageTagInfo
|
||||
ScaStorageThumb scaStorageThumb
|
||||
ScaUserFollow scaUserFollow
|
||||
ScaUserLevel scaUserLevel
|
||||
ScaUserMessage scaUserMessage
|
||||
@@ -126,6 +130,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
|
||||
ScaStorageLocation: q.ScaStorageLocation.clone(db),
|
||||
ScaStorageTag: q.ScaStorageTag.clone(db),
|
||||
ScaStorageTagInfo: q.ScaStorageTagInfo.clone(db),
|
||||
ScaStorageThumb: q.ScaStorageThumb.clone(db),
|
||||
ScaUserFollow: q.ScaUserFollow.clone(db),
|
||||
ScaUserLevel: q.ScaUserLevel.clone(db),
|
||||
ScaUserMessage: q.ScaUserMessage.clone(db),
|
||||
@@ -158,6 +163,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
|
||||
ScaStorageLocation: q.ScaStorageLocation.replaceDB(db),
|
||||
ScaStorageTag: q.ScaStorageTag.replaceDB(db),
|
||||
ScaStorageTagInfo: q.ScaStorageTagInfo.replaceDB(db),
|
||||
ScaStorageThumb: q.ScaStorageThumb.replaceDB(db),
|
||||
ScaUserFollow: q.ScaUserFollow.replaceDB(db),
|
||||
ScaUserLevel: q.ScaUserLevel.replaceDB(db),
|
||||
ScaUserMessage: q.ScaUserMessage.replaceDB(db),
|
||||
@@ -180,6 +186,7 @@ type queryCtx struct {
|
||||
ScaStorageLocation IScaStorageLocationDo
|
||||
ScaStorageTag IScaStorageTagDo
|
||||
ScaStorageTagInfo IScaStorageTagInfoDo
|
||||
ScaStorageThumb IScaStorageThumbDo
|
||||
ScaUserFollow IScaUserFollowDo
|
||||
ScaUserLevel IScaUserLevelDo
|
||||
ScaUserMessage IScaUserMessageDo
|
||||
@@ -202,6 +209,7 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
|
||||
ScaStorageLocation: q.ScaStorageLocation.WithContext(ctx),
|
||||
ScaStorageTag: q.ScaStorageTag.WithContext(ctx),
|
||||
ScaStorageTagInfo: q.ScaStorageTagInfo.WithContext(ctx),
|
||||
ScaStorageThumb: q.ScaStorageThumb.WithContext(ctx),
|
||||
ScaUserFollow: q.ScaUserFollow.WithContext(ctx),
|
||||
ScaUserLevel: q.ScaUserLevel.WithContext(ctx),
|
||||
ScaUserMessage: q.ScaUserMessage.WithContext(ctx),
|
||||
|
@@ -46,6 +46,7 @@ func newScaAuthMenu(db *gorm.DB, opts ...gen.DOOption) scaAuthMenu {
|
||||
return _scaAuthMenu
|
||||
}
|
||||
|
||||
// scaAuthMenu 菜单表
|
||||
type scaAuthMenu struct {
|
||||
scaAuthMenuDo
|
||||
|
||||
|
@@ -41,6 +41,7 @@ func newScaAuthPermissionRule(db *gorm.DB, opts ...gen.DOOption) scaAuthPermissi
|
||||
return _scaAuthPermissionRule
|
||||
}
|
||||
|
||||
// scaAuthPermissionRule 接口权限表
|
||||
type scaAuthPermissionRule struct {
|
||||
scaAuthPermissionRuleDo
|
||||
|
||||
|
@@ -39,6 +39,7 @@ func newScaAuthRole(db *gorm.DB, opts ...gen.DOOption) scaAuthRole {
|
||||
return _scaAuthRole
|
||||
}
|
||||
|
||||
// scaAuthRole 角色表
|
||||
type scaAuthRole struct {
|
||||
scaAuthRoleDo
|
||||
|
||||
|
@@ -50,6 +50,7 @@ func newScaAuthUser(db *gorm.DB, opts ...gen.DOOption) scaAuthUser {
|
||||
return _scaAuthUser
|
||||
}
|
||||
|
||||
// scaAuthUser 用户表
|
||||
type scaAuthUser struct {
|
||||
scaAuthUserDo
|
||||
|
||||
|
@@ -50,6 +50,7 @@ func newScaAuthUserDevice(db *gorm.DB, opts ...gen.DOOption) scaAuthUserDevice {
|
||||
return _scaAuthUserDevice
|
||||
}
|
||||
|
||||
// scaAuthUserDevice 用户设备表
|
||||
type scaAuthUserDevice struct {
|
||||
scaAuthUserDeviceDo
|
||||
|
||||
|
@@ -41,6 +41,7 @@ func newScaAuthUserSocial(db *gorm.DB, opts ...gen.DOOption) scaAuthUserSocial {
|
||||
return _scaAuthUserSocial
|
||||
}
|
||||
|
||||
// scaAuthUserSocial 第三方登录信息表
|
||||
type scaAuthUserSocial struct {
|
||||
scaAuthUserSocialDo
|
||||
|
||||
|
@@ -38,6 +38,7 @@ func newScaCommentLike(db *gorm.DB, opts ...gen.DOOption) scaCommentLike {
|
||||
return _scaCommentLike
|
||||
}
|
||||
|
||||
// scaCommentLike 评论点赞表
|
||||
type scaCommentLike struct {
|
||||
scaCommentLikeDo
|
||||
|
||||
|
@@ -55,6 +55,7 @@ func newScaCommentReply(db *gorm.DB, opts ...gen.DOOption) scaCommentReply {
|
||||
return _scaCommentReply
|
||||
}
|
||||
|
||||
// scaCommentReply 评论表
|
||||
type scaCommentReply struct {
|
||||
scaCommentReplyDo
|
||||
|
||||
|
@@ -45,6 +45,7 @@ func newScaMessageReport(db *gorm.DB, opts ...gen.DOOption) scaMessageReport {
|
||||
return _scaMessageReport
|
||||
}
|
||||
|
||||
// scaMessageReport 评论举报表
|
||||
type scaMessageReport struct {
|
||||
scaMessageReportDo
|
||||
|
||||
|
@@ -41,6 +41,7 @@ func newScaStorageAlbum(db *gorm.DB, opts ...gen.DOOption) scaStorageAlbum {
|
||||
return _scaStorageAlbum
|
||||
}
|
||||
|
||||
// scaStorageAlbum 相册信息表
|
||||
type scaStorageAlbum struct {
|
||||
scaStorageAlbumDo
|
||||
|
||||
|
@@ -44,6 +44,7 @@ func newScaStorageConfig(db *gorm.DB, opts ...gen.DOOption) scaStorageConfig {
|
||||
return _scaStorageConfig
|
||||
}
|
||||
|
||||
// scaStorageConfig 用户存储配置表
|
||||
type scaStorageConfig struct {
|
||||
scaStorageConfigDo
|
||||
|
||||
|
@@ -37,6 +37,7 @@ func newScaStorageInfo(db *gorm.DB, opts ...gen.DOOption) scaStorageInfo {
|
||||
_scaStorageInfo.FileType = field.NewString(tableName, "file_type")
|
||||
_scaStorageInfo.Width = field.NewFloat64(tableName, "width")
|
||||
_scaStorageInfo.Height = field.NewFloat64(tableName, "height")
|
||||
_scaStorageInfo.ThumbID = field.NewInt64(tableName, "thumb_id")
|
||||
_scaStorageInfo.Category = field.NewString(tableName, "category")
|
||||
_scaStorageInfo.Tag = field.NewString(tableName, "tag")
|
||||
_scaStorageInfo.Type = field.NewString(tableName, "type")
|
||||
@@ -56,6 +57,7 @@ func newScaStorageInfo(db *gorm.DB, opts ...gen.DOOption) scaStorageInfo {
|
||||
return _scaStorageInfo
|
||||
}
|
||||
|
||||
// scaStorageInfo 文件存储信息表
|
||||
type scaStorageInfo struct {
|
||||
scaStorageInfoDo
|
||||
|
||||
@@ -70,6 +72,7 @@ type scaStorageInfo struct {
|
||||
FileType field.String // 文件类型
|
||||
Width field.Float64 // 宽
|
||||
Height field.Float64 // 高
|
||||
ThumbID field.Int64 // 缩略图id
|
||||
Category field.String // 分类
|
||||
Tag field.String // 标签
|
||||
Type field.String // 类型
|
||||
@@ -109,6 +112,7 @@ func (s *scaStorageInfo) updateTableName(table string) *scaStorageInfo {
|
||||
s.FileType = field.NewString(table, "file_type")
|
||||
s.Width = field.NewFloat64(table, "width")
|
||||
s.Height = field.NewFloat64(table, "height")
|
||||
s.ThumbID = field.NewInt64(table, "thumb_id")
|
||||
s.Category = field.NewString(table, "category")
|
||||
s.Tag = field.NewString(table, "tag")
|
||||
s.Type = field.NewString(table, "type")
|
||||
@@ -138,7 +142,7 @@ func (s *scaStorageInfo) GetFieldByName(fieldName string) (field.OrderExpr, bool
|
||||
}
|
||||
|
||||
func (s *scaStorageInfo) fillFieldMap() {
|
||||
s.fieldMap = make(map[string]field.Expr, 23)
|
||||
s.fieldMap = make(map[string]field.Expr, 24)
|
||||
s.fieldMap["id"] = s.ID
|
||||
s.fieldMap["user_id"] = s.UserID
|
||||
s.fieldMap["provider"] = s.Provider
|
||||
@@ -149,6 +153,7 @@ func (s *scaStorageInfo) fillFieldMap() {
|
||||
s.fieldMap["file_type"] = s.FileType
|
||||
s.fieldMap["width"] = s.Width
|
||||
s.fieldMap["height"] = s.Height
|
||||
s.fieldMap["thumb_id"] = s.ThumbID
|
||||
s.fieldMap["category"] = s.Category
|
||||
s.fieldMap["tag"] = s.Tag
|
||||
s.fieldMap["type"] = s.Type
|
||||
|
@@ -48,6 +48,7 @@ func newScaStorageLocation(db *gorm.DB, opts ...gen.DOOption) scaStorageLocation
|
||||
return _scaStorageLocation
|
||||
}
|
||||
|
||||
// scaStorageLocation 文件地理位置信息表
|
||||
type scaStorageLocation struct {
|
||||
scaStorageLocationDo
|
||||
|
||||
|
@@ -39,6 +39,7 @@ func newScaStorageTag(db *gorm.DB, opts ...gen.DOOption) scaStorageTag {
|
||||
return _scaStorageTag
|
||||
}
|
||||
|
||||
// scaStorageTag 标签表
|
||||
type scaStorageTag struct {
|
||||
scaStorageTagDo
|
||||
|
||||
|
412
app/auth/model/mysql/query/sca_storage_thumb.gen.go
Normal file
412
app/auth/model/mysql/query/sca_storage_thumb.gen.go
Normal file
@@ -0,0 +1,412 @@
|
||||
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"gorm.io/gorm/schema"
|
||||
|
||||
"gorm.io/gen"
|
||||
"gorm.io/gen/field"
|
||||
|
||||
"gorm.io/plugin/dbresolver"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/auth/model/mysql/model"
|
||||
)
|
||||
|
||||
func newScaStorageThumb(db *gorm.DB, opts ...gen.DOOption) scaStorageThumb {
|
||||
_scaStorageThumb := scaStorageThumb{}
|
||||
|
||||
_scaStorageThumb.scaStorageThumbDo.UseDB(db, opts...)
|
||||
_scaStorageThumb.scaStorageThumbDo.UseModel(&model.ScaStorageThumb{})
|
||||
|
||||
tableName := _scaStorageThumb.scaStorageThumbDo.TableName()
|
||||
_scaStorageThumb.ALL = field.NewAsterisk(tableName)
|
||||
_scaStorageThumb.ID = field.NewInt64(tableName, "id")
|
||||
_scaStorageThumb.UserID = field.NewString(tableName, "user_id")
|
||||
_scaStorageThumb.ThumbPath = field.NewString(tableName, "thumb_path")
|
||||
_scaStorageThumb.ThumbW = field.NewFloat64(tableName, "thumb_w")
|
||||
_scaStorageThumb.ThumbH = field.NewFloat64(tableName, "thumb_h")
|
||||
_scaStorageThumb.ThumbSize = field.NewFloat64(tableName, "thumb_size")
|
||||
_scaStorageThumb.CreatedAt = field.NewTime(tableName, "created_at")
|
||||
_scaStorageThumb.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||
_scaStorageThumb.DeletedAt = field.NewField(tableName, "deleted_at")
|
||||
|
||||
_scaStorageThumb.fillFieldMap()
|
||||
|
||||
return _scaStorageThumb
|
||||
}
|
||||
|
||||
type scaStorageThumb struct {
|
||||
scaStorageThumbDo
|
||||
|
||||
ALL field.Asterisk
|
||||
ID field.Int64 // 主键
|
||||
UserID field.String // 用户ID
|
||||
ThumbPath field.String // 缩略图路径
|
||||
ThumbW field.Float64 // 缩略图宽
|
||||
ThumbH field.Float64 // 缩略图高
|
||||
ThumbSize field.Float64 // 缩略图大小
|
||||
CreatedAt field.Time // 创建时间
|
||||
UpdatedAt field.Time // 更新时间
|
||||
DeletedAt field.Field // 删除时间
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
}
|
||||
|
||||
func (s scaStorageThumb) Table(newTableName string) *scaStorageThumb {
|
||||
s.scaStorageThumbDo.UseTable(newTableName)
|
||||
return s.updateTableName(newTableName)
|
||||
}
|
||||
|
||||
func (s scaStorageThumb) As(alias string) *scaStorageThumb {
|
||||
s.scaStorageThumbDo.DO = *(s.scaStorageThumbDo.As(alias).(*gen.DO))
|
||||
return s.updateTableName(alias)
|
||||
}
|
||||
|
||||
func (s *scaStorageThumb) updateTableName(table string) *scaStorageThumb {
|
||||
s.ALL = field.NewAsterisk(table)
|
||||
s.ID = field.NewInt64(table, "id")
|
||||
s.UserID = field.NewString(table, "user_id")
|
||||
s.ThumbPath = field.NewString(table, "thumb_path")
|
||||
s.ThumbW = field.NewFloat64(table, "thumb_w")
|
||||
s.ThumbH = field.NewFloat64(table, "thumb_h")
|
||||
s.ThumbSize = field.NewFloat64(table, "thumb_size")
|
||||
s.CreatedAt = field.NewTime(table, "created_at")
|
||||
s.UpdatedAt = field.NewTime(table, "updated_at")
|
||||
s.DeletedAt = field.NewField(table, "deleted_at")
|
||||
|
||||
s.fillFieldMap()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *scaStorageThumb) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
||||
_f, ok := s.fieldMap[fieldName]
|
||||
if !ok || _f == nil {
|
||||
return nil, false
|
||||
}
|
||||
_oe, ok := _f.(field.OrderExpr)
|
||||
return _oe, ok
|
||||
}
|
||||
|
||||
func (s *scaStorageThumb) fillFieldMap() {
|
||||
s.fieldMap = make(map[string]field.Expr, 9)
|
||||
s.fieldMap["id"] = s.ID
|
||||
s.fieldMap["user_id"] = s.UserID
|
||||
s.fieldMap["thumb_path"] = s.ThumbPath
|
||||
s.fieldMap["thumb_w"] = s.ThumbW
|
||||
s.fieldMap["thumb_h"] = s.ThumbH
|
||||
s.fieldMap["thumb_size"] = s.ThumbSize
|
||||
s.fieldMap["created_at"] = s.CreatedAt
|
||||
s.fieldMap["updated_at"] = s.UpdatedAt
|
||||
s.fieldMap["deleted_at"] = s.DeletedAt
|
||||
}
|
||||
|
||||
func (s scaStorageThumb) clone(db *gorm.DB) scaStorageThumb {
|
||||
s.scaStorageThumbDo.ReplaceConnPool(db.Statement.ConnPool)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s scaStorageThumb) replaceDB(db *gorm.DB) scaStorageThumb {
|
||||
s.scaStorageThumbDo.ReplaceDB(db)
|
||||
return s
|
||||
}
|
||||
|
||||
type scaStorageThumbDo struct{ gen.DO }
|
||||
|
||||
type IScaStorageThumbDo interface {
|
||||
gen.SubQuery
|
||||
Debug() IScaStorageThumbDo
|
||||
WithContext(ctx context.Context) IScaStorageThumbDo
|
||||
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
|
||||
ReplaceDB(db *gorm.DB)
|
||||
ReadDB() IScaStorageThumbDo
|
||||
WriteDB() IScaStorageThumbDo
|
||||
As(alias string) gen.Dao
|
||||
Session(config *gorm.Session) IScaStorageThumbDo
|
||||
Columns(cols ...field.Expr) gen.Columns
|
||||
Clauses(conds ...clause.Expression) IScaStorageThumbDo
|
||||
Not(conds ...gen.Condition) IScaStorageThumbDo
|
||||
Or(conds ...gen.Condition) IScaStorageThumbDo
|
||||
Select(conds ...field.Expr) IScaStorageThumbDo
|
||||
Where(conds ...gen.Condition) IScaStorageThumbDo
|
||||
Order(conds ...field.Expr) IScaStorageThumbDo
|
||||
Distinct(cols ...field.Expr) IScaStorageThumbDo
|
||||
Omit(cols ...field.Expr) IScaStorageThumbDo
|
||||
Join(table schema.Tabler, on ...field.Expr) IScaStorageThumbDo
|
||||
LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageThumbDo
|
||||
RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageThumbDo
|
||||
Group(cols ...field.Expr) IScaStorageThumbDo
|
||||
Having(conds ...gen.Condition) IScaStorageThumbDo
|
||||
Limit(limit int) IScaStorageThumbDo
|
||||
Offset(offset int) IScaStorageThumbDo
|
||||
Count() (count int64, err error)
|
||||
Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageThumbDo
|
||||
Unscoped() IScaStorageThumbDo
|
||||
Create(values ...*model.ScaStorageThumb) error
|
||||
CreateInBatches(values []*model.ScaStorageThumb, batchSize int) error
|
||||
Save(values ...*model.ScaStorageThumb) error
|
||||
First() (*model.ScaStorageThumb, error)
|
||||
Take() (*model.ScaStorageThumb, error)
|
||||
Last() (*model.ScaStorageThumb, error)
|
||||
Find() ([]*model.ScaStorageThumb, error)
|
||||
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageThumb, err error)
|
||||
FindInBatches(result *[]*model.ScaStorageThumb, batchSize int, fc func(tx gen.Dao, batch int) error) error
|
||||
Pluck(column field.Expr, dest interface{}) error
|
||||
Delete(...*model.ScaStorageThumb) (info gen.ResultInfo, err error)
|
||||
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
|
||||
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
|
||||
Updates(value interface{}) (info gen.ResultInfo, err error)
|
||||
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
|
||||
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
|
||||
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
|
||||
UpdateFrom(q gen.SubQuery) gen.Dao
|
||||
Attrs(attrs ...field.AssignExpr) IScaStorageThumbDo
|
||||
Assign(attrs ...field.AssignExpr) IScaStorageThumbDo
|
||||
Joins(fields ...field.RelationField) IScaStorageThumbDo
|
||||
Preload(fields ...field.RelationField) IScaStorageThumbDo
|
||||
FirstOrInit() (*model.ScaStorageThumb, error)
|
||||
FirstOrCreate() (*model.ScaStorageThumb, error)
|
||||
FindByPage(offset int, limit int) (result []*model.ScaStorageThumb, count int64, err error)
|
||||
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
|
||||
Scan(result interface{}) (err error)
|
||||
Returning(value interface{}, columns ...string) IScaStorageThumbDo
|
||||
UnderlyingDB() *gorm.DB
|
||||
schema.Tabler
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Debug() IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Debug())
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) WithContext(ctx context.Context) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.WithContext(ctx))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) ReadDB() IScaStorageThumbDo {
|
||||
return s.Clauses(dbresolver.Read)
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) WriteDB() IScaStorageThumbDo {
|
||||
return s.Clauses(dbresolver.Write)
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Session(config *gorm.Session) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Session(config))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Clauses(conds ...clause.Expression) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Clauses(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Returning(value interface{}, columns ...string) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Returning(value, columns...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Not(conds ...gen.Condition) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Not(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Or(conds ...gen.Condition) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Or(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Select(conds ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Select(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Where(conds ...gen.Condition) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Where(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Order(conds ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Order(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Distinct(cols ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Distinct(cols...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Omit(cols ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Omit(cols...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Join(table schema.Tabler, on ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Join(table, on...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) LeftJoin(table schema.Tabler, on ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.LeftJoin(table, on...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) RightJoin(table schema.Tabler, on ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.RightJoin(table, on...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Group(cols ...field.Expr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Group(cols...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Having(conds ...gen.Condition) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Having(conds...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Limit(limit int) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Limit(limit))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Offset(offset int) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Offset(offset))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Scopes(funcs...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Unscoped() IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Unscoped())
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Create(values ...*model.ScaStorageThumb) error {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
return s.DO.Create(values)
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) CreateInBatches(values []*model.ScaStorageThumb, batchSize int) error {
|
||||
return s.DO.CreateInBatches(values, batchSize)
|
||||
}
|
||||
|
||||
// Save : !!! underlying implementation is different with GORM
|
||||
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||
func (s scaStorageThumbDo) Save(values ...*model.ScaStorageThumb) error {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
return s.DO.Save(values)
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) First() (*model.ScaStorageThumb, error) {
|
||||
if result, err := s.DO.First(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*model.ScaStorageThumb), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Take() (*model.ScaStorageThumb, error) {
|
||||
if result, err := s.DO.Take(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*model.ScaStorageThumb), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Last() (*model.ScaStorageThumb, error) {
|
||||
if result, err := s.DO.Last(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*model.ScaStorageThumb), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Find() ([]*model.ScaStorageThumb, error) {
|
||||
result, err := s.DO.Find()
|
||||
return result.([]*model.ScaStorageThumb), err
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ScaStorageThumb, err error) {
|
||||
buf := make([]*model.ScaStorageThumb, 0, batchSize)
|
||||
err = s.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
|
||||
defer func() { results = append(results, buf...) }()
|
||||
return fc(tx, batch)
|
||||
})
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) FindInBatches(result *[]*model.ScaStorageThumb, batchSize int, fc func(tx gen.Dao, batch int) error) error {
|
||||
return s.DO.FindInBatches(result, batchSize, fc)
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Attrs(attrs ...field.AssignExpr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Attrs(attrs...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Assign(attrs ...field.AssignExpr) IScaStorageThumbDo {
|
||||
return s.withDO(s.DO.Assign(attrs...))
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Joins(fields ...field.RelationField) IScaStorageThumbDo {
|
||||
for _, _f := range fields {
|
||||
s = *s.withDO(s.DO.Joins(_f))
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Preload(fields ...field.RelationField) IScaStorageThumbDo {
|
||||
for _, _f := range fields {
|
||||
s = *s.withDO(s.DO.Preload(_f))
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) FirstOrInit() (*model.ScaStorageThumb, error) {
|
||||
if result, err := s.DO.FirstOrInit(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*model.ScaStorageThumb), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) FirstOrCreate() (*model.ScaStorageThumb, error) {
|
||||
if result, err := s.DO.FirstOrCreate(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return result.(*model.ScaStorageThumb), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) FindByPage(offset int, limit int) (result []*model.ScaStorageThumb, count int64, err error) {
|
||||
result, err = s.Offset(offset).Limit(limit).Find()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if size := len(result); 0 < limit && 0 < size && size < limit {
|
||||
count = int64(size + offset)
|
||||
return
|
||||
}
|
||||
|
||||
count, err = s.Offset(-1).Limit(-1).Count()
|
||||
return
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
|
||||
count, err = s.Count()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = s.Offset(offset).Limit(limit).Scan(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Scan(result interface{}) (err error) {
|
||||
return s.DO.Scan(result)
|
||||
}
|
||||
|
||||
func (s scaStorageThumbDo) Delete(models ...*model.ScaStorageThumb) (result gen.ResultInfo, err error) {
|
||||
return s.DO.Delete(models)
|
||||
}
|
||||
|
||||
func (s *scaStorageThumbDo) withDO(do gen.Dao) *scaStorageThumbDo {
|
||||
s.DO = *do.(*gen.DO)
|
||||
return s
|
||||
}
|
@@ -40,6 +40,7 @@ func newScaUserFollow(db *gorm.DB, opts ...gen.DOOption) scaUserFollow {
|
||||
return _scaUserFollow
|
||||
}
|
||||
|
||||
// scaUserFollow 用户关注表
|
||||
type scaUserFollow struct {
|
||||
scaUserFollowDo
|
||||
|
||||
|
@@ -44,6 +44,7 @@ func newScaUserLevel(db *gorm.DB, opts ...gen.DOOption) scaUserLevel {
|
||||
return _scaUserLevel
|
||||
}
|
||||
|
||||
// scaUserLevel 用户等级表
|
||||
type scaUserLevel struct {
|
||||
scaUserLevelDo
|
||||
|
||||
|
@@ -42,6 +42,7 @@ func newScaUserMessage(db *gorm.DB, opts ...gen.DOOption) scaUserMessage {
|
||||
return _scaUserMessage
|
||||
}
|
||||
|
||||
// scaUserMessage 用户消息表
|
||||
type scaUserMessage struct {
|
||||
scaUserMessageDo
|
||||
|
||||
|
7
common/constant/bucket_name.go
Normal file
7
common/constant/bucket_name.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package constant
|
||||
|
||||
const (
|
||||
FaceBucketName = "schisandra-face-samples"
|
||||
CommentImagesBucketName = "schisandra-comment-images"
|
||||
ThumbnailBucketName = "schisandra-thumbnail-images"
|
||||
)
|
6
common/constant/mq_topic.go
Normal file
6
common/constant/mq_topic.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package constant
|
||||
|
||||
const (
|
||||
MQTopicImageProcess = "image-process-topic"
|
||||
MQTopicCommentLike = "comment-like-topic"
|
||||
)
|
@@ -1,6 +0,0 @@
|
||||
package constant
|
||||
|
||||
const (
|
||||
FaceBucketName = "faces"
|
||||
CommentImagesBucketName = "comments"
|
||||
)
|
@@ -22,7 +22,7 @@ const (
|
||||
|
||||
const (
|
||||
ImageListPrefix = "image:list:"
|
||||
ImageListMetaPrefix = "image:meta:"
|
||||
ImageRecentPrefix = "image:recent:"
|
||||
ImageFaceListPrefix = "image:face:list:"
|
||||
ImageFaceListPrefix = "image:faces:"
|
||||
ImageSinglePrefix = "image:single:"
|
||||
)
|
||||
|
27
common/nsqx/docker-compose.yml
Normal file
27
common/nsqx/docker-compose.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
version: '3'
|
||||
services:
|
||||
nsqlookupd:
|
||||
image: nsqio/nsq
|
||||
command: /nsqlookupd
|
||||
ports:
|
||||
- "4160:4160"
|
||||
- "4161:4161"
|
||||
|
||||
nsqd:
|
||||
image: nsqio/nsq
|
||||
command: /nsqd --mem-queue-size=0 -data-path=/data --broadcast-address=1.95.0.111 --lookupd-tcp-address=nsqlookupd:4160
|
||||
depends_on:
|
||||
- nsqlookupd
|
||||
volumes:
|
||||
- ./nsqd/data:/data
|
||||
ports:
|
||||
- "4150:4150"
|
||||
- "4151:4151"
|
||||
|
||||
nsqadmin:
|
||||
image: nsqio/nsq
|
||||
command: /nsqadmin --lookupd-http-address=nsqlookupd:4161
|
||||
depends_on:
|
||||
- nsqlookupd
|
||||
ports:
|
||||
- "4171:4171"
|
28
common/nsqx/nsq.go
Normal file
28
common/nsqx/nsq.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package nsqx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/nsqio/go-nsq"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewNsqProducer(url string) *nsq.Producer {
|
||||
producer, err := nsq.NewProducer(url, nsq.NewConfig())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
producer.SetLoggerLevel(nsq.LogLevelError)
|
||||
return producer
|
||||
}
|
||||
|
||||
func NewNSQConsumer(topic string) *nsq.Consumer {
|
||||
config := nsq.NewConfig()
|
||||
config.LookupdPollInterval = 15 * time.Second
|
||||
consumer, err := nsq.NewConsumer(topic, "channel", config)
|
||||
if err != nil {
|
||||
fmt.Printf("InitNSQ consumer error: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
consumer.SetLoggerLevel(nsq.LogLevelError)
|
||||
return consumer
|
||||
}
|
41
common/utils/bytes_to_file.go
Normal file
41
common/utils/bytes_to_file.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
)
|
||||
|
||||
// ByteReader 实现了 multipart.File 接口
|
||||
type ByteReader struct {
|
||||
data []byte
|
||||
index int
|
||||
}
|
||||
|
||||
func (r *ByteReader) Read(p []byte) (n int, err error) {
|
||||
if r.index >= len(r.data) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n = copy(p, r.data[r.index:])
|
||||
r.index += n
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (r *ByteReader) Seek(offset int64, whence int) (int64, error) {
|
||||
return 0, fmt.Errorf("Seek not implemented")
|
||||
}
|
||||
|
||||
func (r *ByteReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, fmt.Errorf("ReadAt not implemented")
|
||||
}
|
||||
|
||||
// 实现 Close 方法,符合 multipart.File 接口
|
||||
func (r *ByteReader) Close() error {
|
||||
// 这里没有实际需要清理的资源,但必须实现 Close 方法
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToMultipartFile 将 []byte 转换为 multipart.File
|
||||
func ToMultipartFile(data []byte) multipart.File {
|
||||
return &ByteReader{data: data}
|
||||
}
|
41
go.mod
41
go.mod
@@ -4,7 +4,7 @@ go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.1
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.3
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.6
|
||||
github.com/Kagami/go-face v0.0.0-20210630145111-0c14797b4d0e
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.0
|
||||
github.com/asjdf/gorm-cache v1.2.3
|
||||
@@ -18,23 +18,25 @@ require (
|
||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20241220152942-06eb5c6e8230
|
||||
github.com/lxzan/gws v1.8.8
|
||||
github.com/microcosm-cc/bluemonday v1.0.27
|
||||
github.com/minio/minio-go/v7 v7.0.84
|
||||
github.com/minio/minio-go/v7 v7.0.85
|
||||
github.com/mssola/useragent v1.0.0
|
||||
github.com/nicksnyder/go-i18n/v2 v2.5.1
|
||||
github.com/nsqio/go-nsq v1.1.0
|
||||
github.com/paulmach/orb v0.11.1
|
||||
github.com/pelletier/go-toml/v2 v2.2.3
|
||||
github.com/pkg6/go-sms v0.1.2
|
||||
github.com/redis/go-redis/v9 v9.7.0
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.60
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.61
|
||||
github.com/wenlng/go-captcha-assets v1.0.1
|
||||
github.com/wenlng/go-captcha/v2 v2.0.2
|
||||
github.com/yitter/idgenerator-go v1.3.3
|
||||
github.com/zeromicro/go-zero v1.8.0
|
||||
github.com/zmexing/go-sensitive-word v1.3.0
|
||||
gocv.io/x/gocv v0.40.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/text v0.22.0
|
||||
google.golang.org/grpc v1.70.0
|
||||
google.golang.org/protobuf v1.36.4
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gen v0.3.26
|
||||
gorm.io/gorm v1.25.12
|
||||
@@ -60,6 +62,7 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/dolthub/maphash v0.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
@@ -83,14 +86,15 @@ require (
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 // indirect
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/imroc/req/v3 v3.49.1 // indirect
|
||||
@@ -122,7 +126,6 @@ require (
|
||||
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/paulmach/orb v0.11.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg6/go-requests v0.2.3 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
@@ -135,8 +138,6 @@ require (
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tidwall/geoindex v1.7.0 // indirect
|
||||
github.com/tidwall/rtree v1.10.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.18 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.18 // indirect
|
||||
@@ -158,18 +159,18 @@ require (
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/oauth2 v0.26.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/term v0.29.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 // indirect
|
||||
golang.org/x/tools v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -178,16 +179,16 @@ require (
|
||||
gorm.io/driver/postgres v1.5.11 // indirect
|
||||
gorm.io/driver/sqlserver v1.5.4 // indirect
|
||||
gorm.io/hints v1.1.2 // indirect
|
||||
k8s.io/api v0.32.1 // indirect
|
||||
k8s.io/apimachinery v0.32.1 // indirect
|
||||
k8s.io/client-go v0.32.1 // indirect
|
||||
k8s.io/api v0.32.2 // indirect
|
||||
k8s.io/apimachinery v0.32.2 // indirect
|
||||
k8s.io/client-go v0.32.2 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
modernc.org/libc v1.61.11 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.34.5 // indirect
|
||||
modernc.org/sqlite v1.35.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
|
89
go.sum
89
go.sum
@@ -4,8 +4,8 @@ github.com/ArtisanCloud/PowerLibs/v3 v3.3.1 h1:SsxBygxATQpFS92pKuVtGrgdawwsscj9Y
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.1/go.mod h1:xFGsskCnzAu+6rFEJbGVAlwhrwZPXAny6m7j71S/B5k=
|
||||
github.com/ArtisanCloud/PowerSocialite/v3 v3.0.7 h1:P+erNlErr+X2v7Et+yTWaTfIRhw+HfpAPdvNIEwk9Gw=
|
||||
github.com/ArtisanCloud/PowerSocialite/v3 v3.0.7/go.mod h1:VZQNCvcK/rldF3QaExiSl1gJEAkyc5/I8RLOd3WFZq4=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.3 h1:DoXg2PcUJtVhC9Ly28C1Xhmug2Si023VbTBRoY49xPY=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.3/go.mod h1:J9Soww8NJcB5DVAJSrpjEpAj0y7bdwBD1wdpR8xPeqk=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.6 h1:63LAZisWFAN+2B1fTPNTkbPjiDn8pIL+yS9lbDxUvhQ=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.6/go.mod h1:nIs82Blb0W8QoD6qCx01Lp1W/kM+/n18BgX10UcRIkQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
|
||||
@@ -85,6 +85,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ=
|
||||
@@ -148,6 +150,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -161,8 +165,8 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 h1:wlQI2cYY0BsWmmPPAnxfQ8SDW0S3Jasn+4B8kXFxprg=
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -172,8 +176,8 @@ github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 h1:VD1gqscl4nYs1YxVuSdemTrSgTKrwOWDK0FVFMqm+Cg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0/go.mod h1:4EgsQoS4TOhJizV+JTFg40qx1Ofh3XmXEQNBpgvNT40=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -248,8 +252,8 @@ github.com/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3ao
|
||||
github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.84 h1:D1HVmAF8JF8Bpi6IU4V9vIEj+8pc+xU88EWMs2yed0E=
|
||||
github.com/minio/minio-go/v7 v7.0.84/go.mod h1:57YXpvc5l3rjPdhqNrDsvVlY0qPI6UTk1bflAe+9doY=
|
||||
github.com/minio/minio-go/v7 v7.0.85 h1:9psTLS/NTvC3MWoyjhjXpwcKoNbkongaCSF3PNpSuXo=
|
||||
github.com/minio/minio-go/v7 v7.0.85/go.mod h1:57YXpvc5l3rjPdhqNrDsvVlY0qPI6UTk1bflAe+9doY=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
@@ -274,6 +278,8 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
|
||||
github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=
|
||||
github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
@@ -346,15 +352,9 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.60 h1:/e/tmvRmfKexr/QQIBzWhOkZWsmY3EK72NrI6G/Tv0o=
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.60/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0=
|
||||
github.com/tidwall/cities v0.1.0/go.mod h1:lV/HDp2gCcRcHJWqgt6Di54GiDrTZwh1aG2ZUPNbqa4=
|
||||
github.com/tidwall/geoindex v1.7.0 h1:jtk41sfgwIt8MEDyC3xyKSj75iXXf6rjReJGDNPtR5o=
|
||||
github.com/tidwall/geoindex v1.7.0/go.mod h1:rvVVNEFfkJVWGUdEfU8QaoOg/9zFX0h9ofWzA60mz1I=
|
||||
github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.61 h1:tKNIjvsezkdtajqE887XAw1VL8Pq1HNtpc7rfgz25lA=
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.61/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/rtree v1.10.0 h1:+EcI8fboEaW1L3/9oW/6AMoQ8HiEIHyR7bQOGnmz4Mg=
|
||||
github.com/tidwall/rtree v1.10.0/go.mod h1:iDJQ9NBRtbfKkzZu02za+mIlaP+bjYPnunbSNidpbCQ=
|
||||
github.com/wenlng/go-captcha-assets v1.0.1 h1:AdjRFMKmadPRWRTv0XEYfjDvcaayZ2yExITDvlK/7bk=
|
||||
github.com/wenlng/go-captcha-assets v1.0.1/go.mod h1:yQqc7rRbxgLCg+tWtVp+7Y317D1wIZDan/yIwt8wSac=
|
||||
github.com/wenlng/go-captcha/v2 v2.0.2 h1:8twz6pI6xZwPvEGFezoFX395oFso1MuOlJt/tLiv7pk=
|
||||
@@ -438,10 +438,11 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||
@@ -471,8 +472,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
|
||||
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -541,22 +542,22 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 h1:fCuMM4fowGzigT89NCIsW57Pk9k2D12MMi2ODn+Nk+o=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:5bKytslY8ViY0Cj/ewmRtrWHW64bNF03cAatUUFCdFI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b h1:i+d0RZa8Hs2L/MuaOQYI+krthcxdEbEM2N+Tf3kJ4zk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
@@ -599,12 +600,12 @@ gorm.io/plugin/dbresolver v1.5.3 h1:wFwINGZZmttuu9h7XpvbDHd8Lf9bb8GNzp/NpAMV2wU=
|
||||
gorm.io/plugin/dbresolver v1.5.3/go.mod h1:TSrVhaUg2DZAWP3PrHlDlITEJmNOkL0tFTjvTEsQ4XE=
|
||||
gorm.io/plugin/optimisticlock v1.1.3 h1:uFK8zz+Ln6ju3vGkTd1LY3xR2VBmMxjdU12KBb58PBA=
|
||||
gorm.io/plugin/optimisticlock v1.1.3/go.mod h1:S+MH7qnHGQHxDBc9phjgN+DpNPn/qESd1q69fA3dtkg=
|
||||
k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=
|
||||
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
|
||||
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
|
||||
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=
|
||||
k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=
|
||||
k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw=
|
||||
k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y=
|
||||
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
|
||||
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA=
|
||||
k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg=
|
||||
@@ -613,14 +614,14 @@ k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJ
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.23.15 h1:wFDan71KnYqeHz4eF63vmGE6Q6Pc0PUGDpP0PRMYjDc=
|
||||
modernc.org/ccgo/v4 v4.23.15/go.mod h1:nJX30dks/IWuBOnVa7VRii9Me4/9TZ1SC9GNtmARTy0=
|
||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.6.2 h1:YBXi5Kqp6aCK3fIxwKQ3/fErvawVKwjOLItxj1brGds=
|
||||
modernc.org/gc/v2 v2.6.2/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.11 h1:6sZG8uB6EMMG7iTLPTndi8jyTdgAQNIeLGjCFICACZw=
|
||||
modernc.org/libc v1.61.11/go.mod h1:HHX+srFdn839oaJRd0W8hBM3eg+mieyZCAjWwB08/nM=
|
||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
||||
@@ -629,8 +630,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
|
||||
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
|
||||
modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw=
|
||||
modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
Reference in New Issue
Block a user