diff --git a/aisvc.Dockerfile b/aisvc.Dockerfile index 107634b..b4cc04a 100644 --- a/aisvc.Dockerfile +++ b/aisvc.Dockerfile @@ -1,5 +1,5 @@ # to build this docker image: -# docker build --build-arg OPENCV_VERSION="4.11.0" -f aisvc.Dockerfile -t schisandra-ai-server . +# docker build --build-arg OPENCV_VERSION="4.11.0" -f aisvc.Dockerfile -t landaiqing/schisandra-ai-server:v1.0.0 . # docker build --build-arg OPENCV_VERSION="4.x" --build-arg OPENCV_FILE="https://github.com/opencv/opencv/archive/refs/heads/4.x.zip" --build-arg OPENCV_CONTRIB_FILE="https://github.com/opencv/opencv_contrib/archive/refs/heads/4.x.zip" -f opencv.Dockerfile -t schisandra-cloud-album-server . FROM golang:1.23.5-bullseye AS builder @@ -84,9 +84,10 @@ ENV TZ=Asia/Shanghai \ DEBIAN_FRONTEND=noninteractive RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ - apt-get update && apt-get install -y --no-install-recommends \ + apt-get update --fix-missing && apt-get install -y --no-install-recommends \ tzdata libjpeg62-turbo libblas3 liblapack3 libdlib-dev libtiff5 && \ - rm -rf /var/lib/apt/lists/* + rm -rf /var/lib/apt/lists/* && \ + mkdir -p /app/rpc/etc WORKDIR /app @@ -96,7 +97,7 @@ COPY --from=builder /usr/local/include/opencv4 /usr/local/include/opencv4/ COPY --from=builder /app/schisandra-ai-server . -COPY --from=builder /app/app/aisvc/rpc/etc ./rpc/etc +#COPY --from=builder /app/app/aisvc/rpc/etc ./rpc/etc COPY --from=builder /app/app/aisvc/resources ./resources @@ -105,3 +106,6 @@ ENV LD_LIBRARY_PATH=/usr/local/lib EXPOSE 8888 CMD ["./schisandra-ai-server"] + + +# docker run -p 8888:8888 -v /home/schisandra/backed/aisvc/aisvc.yaml:/app/rpc/etc/aisvc.yaml --name schisandra-ai-server --restart unless-stopped landaiqing/schisandra-ai-server:v1.0.0 \ No newline at end of file diff --git a/app/auth/api/auth.api b/app/auth/api/auth.api index 989f373..85032f1 100644 --- a/app/auth/api/auth.api +++ b/app/auth/api/auth.api @@ -437,6 +437,7 @@ type ( Endpoint string `json:"endpoint"` Bucket string `json:"bucket"` Region string `json:"region"` + Capacity int64 `json:"capacity"` } FaceSampleLibrary { ID int64 `json:"id"` @@ -497,6 +498,7 @@ type ( ID int64 `json:"id"` Provider string `json:"provider"` Bucket string `json:"bucket"` + Type int64 `json:"type"` } // 相册详情响应参数 AlbumDetailListResponse { @@ -781,26 +783,14 @@ type ( ExpireDate string `json:"expire_date"` AccessLimit int64 `json:"access_limit,omitempty"` AccessPassword string `json:"access_password,omitempty"` - Provider string `json:"provider"` - Bucket string `json:"bucket"` Images []ShareImageMeta `json:"images"` } QueryShareImageRequest { InviteCode string `json:"invite_code"` AccessPassword string `json:"access_password,omitempty"` } - ShareImageListMeta { - ID int64 `json:"id"` - FileName string `json:"file_name"` - URL string `json:"url"` - Thumbnail string `json:"thumbnail"` - Width float64 `json:"width"` - Height float64 `json:"height"` - ThumbSize float64 `json:"thumb_size"` - CreatedAt string `json:"created_at"` - } QueryShareImageResponse { - Records []ShareImageListMeta `json:"records"` + Records []AllImageDetail `json:"records"` } ShareRecordListRequest { DateRange []string `json:"date_range"` diff --git a/app/auth/api/etc/auth.yaml b/app/auth/api/etc/auth.yaml index ea9b8e7..38f6d78 100644 --- a/app/auth/api/etc/auth.yaml +++ b/app/auth/api/etc/auth.yaml @@ -92,8 +92,6 @@ Encrypt: Key: p3380puliiep184buh8d5dvujeerqtem # 向量 (16) IV: spb7er04k2vz3dtk - PublicKey: api/etc/rsa_public_key.pem - PrivateKey: api/etc/rsa_private_key.pem # Redis 配置 Redis: # Redis 地址 diff --git a/app/auth/api/internal/logic/share/query_share_image_logic.go b/app/auth/api/internal/logic/share/query_share_image_logic.go index 803bb88..f94aac2 100644 --- a/app/auth/api/internal/logic/share/query_share_image_logic.go +++ b/app/auth/api/internal/logic/share/query_share_image_logic.go @@ -11,8 +11,7 @@ import ( "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/common/constant" - "schisandra-album-cloud-microservices/common/encrypt" - storageConfig "schisandra-album-cloud-microservices/common/storage/config" + "sync" "time" "schisandra-album-cloud-microservices/app/auth/api/internal/svc" @@ -27,6 +26,16 @@ type QueryShareImageLogic struct { svcCtx *svc.ServiceContext } +var WeekdayMap = map[time.Weekday]string{ + time.Sunday: "日", + time.Monday: "一", + time.Tuesday: "二", + time.Wednesday: "三", + time.Thursday: "四", + time.Friday: "五", + time.Saturday: "六", +} + func NewQueryShareImageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryShareImageLogic { return &QueryShareImageLogic{ Logger: logx.WithContext(ctx), @@ -139,24 +148,11 @@ func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.Sca if err != nil { return nil, err } - - // 加载用户oss配置信息 - cacheOssConfigKey := constant.UserOssConfigPrefix + storageShare.UserID + ":" + storageShare.Provider - ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, storageShare.UserID, storageShare.Provider) - if err != nil { - return nil, err - } - - service, err := l.svcCtx.StorageManager.GetStorage(storageShare.UserID, ossConfig) - if err != nil { - return nil, errors.New("get storage failed") - } - + reqParams := make(url.Values) // 使用 errgroup 和 semaphore 并发处理图片信息 - var ResultList []types.ShareImageListMeta g, ctx := errgroup.WithContext(l.ctx) sem := semaphore.NewWeighted(10) // 限制并发数为 10 - + groupedImages := sync.Map{} for _, imgInfo := range storageInfoList { imgInfo := imgInfo // 创建局部变量,避免闭包问题 if err := sem.Acquire(ctx, 1); err != nil { @@ -164,25 +160,32 @@ func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.Sca } g.Go(func() error { defer sem.Release(1) - ossURL, err := service.PresignedURL(ctx, ossConfig.BucketName, imgInfo.Path, 30*time.Minute) + + // 生成日期分类键 + weekday := WeekdayMap[imgInfo.CreatedAt.Weekday()] + date := imgInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) + + ossUrl, err := l.svcCtx.MinioClient.PresignedGetObject(ctx, constant.ShareImagesBucketName, imgInfo.Path, 30*time.Minute, reqParams) if err != nil { return errors.New("get presigned url failed") } - reqParams := make(url.Values) presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(ctx, constant.ThumbnailBucketName, imgInfo.ThumbPath, 30*time.Minute, reqParams) if err != nil { return errors.New("get presigned thumbnail url failed") } - ResultList = append(ResultList, types.ShareImageListMeta{ + // 原子操作更新分组数据 + value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{}) + images := value.([]types.ImageMeta) + images = append(images, types.ImageMeta{ ID: imgInfo.ID, FileName: imgInfo.FileName, Height: imgInfo.ThumbH, Width: imgInfo.ThumbW, - ThumbSize: imgInfo.ThumbSize, CreatedAt: imgInfo.CreatedAt.Format(constant.TimeFormat), - URL: ossURL, + URL: ossUrl.String(), Thumbnail: presignedURL.String(), }) + groupedImages.Store(date, images) return nil }) } @@ -192,8 +195,17 @@ func (l *QueryShareImageLogic) queryShareImageFromSource(storageShare *model.Sca return nil, err } + // 转换为切片并排序 + var imageList []types.AllImageDetail + groupedImages.Range(func(key, value interface{}) bool { + imageList = append(imageList, types.AllImageDetail{ + Date: key.(string), + List: value.([]types.ImageMeta), + }) + return true + }) return &types.QueryShareImageResponse{ - Records: ResultList}, nil + Records: imageList}, nil } func (l *QueryShareImageLogic) recordUserVisit(shareID int64, userID string) error { @@ -255,63 +267,3 @@ func (l *QueryShareImageLogic) incrementVisitCount(shareCode string, limit int64 return nil } - -// 提取解密操作为函数 -func (l *QueryShareImageLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) { - accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key) - if err != nil { - return nil, errors.New("decrypt access key failed") - } - secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key) - if err != nil { - return nil, errors.New("decrypt secret key failed") - } - return &storageConfig.StorageConfig{ - Provider: config.Provider, - Endpoint: config.Endpoint, - AccessKey: accessKey, - SecretKey: secretKey, - BucketName: config.Bucket, - Region: config.Region, - }, nil -} - -// 从缓存或数据库中获取 OSS 配置 -func (l *QueryShareImageLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) { - result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result() - if err != nil && !errors.Is(err, redis.Nil) { - return nil, errors.New("get oss config failed") - } - - var ossConfig *storageConfig.StorageConfig - if result != "" { - var redisOssConfig model.ScaStorageConfig - if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil { - return nil, errors.New("unmarshal oss config failed") - } - return l.decryptConfig(&redisOssConfig) - } - - // 缓存未命中,从数据库中加载 - scaOssConfig := l.svcCtx.DB.ScaStorageConfig - dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First() - if err != nil { - return nil, err - } - - // 缓存数据库配置 - ossConfig, err = l.decryptConfig(dbOssConfig) - if err != nil { - return nil, err - } - marshalData, err := json.Marshal(dbOssConfig) - if err != nil { - return nil, errors.New("marshal oss config failed") - } - err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err() - if err != nil { - return nil, errors.New("set oss config failed") - } - - return ossConfig, nil -} diff --git a/app/auth/api/internal/logic/share/upload_share_image_logic.go b/app/auth/api/internal/logic/share/upload_share_image_logic.go index 0f4740c..d95135c 100644 --- a/app/auth/api/internal/logic/share/upload_share_image_logic.go +++ b/app/auth/api/internal/logic/share/upload_share_image_logic.go @@ -9,7 +9,6 @@ import ( "fmt" "github.com/ccpwcn/kgo" "github.com/minio/minio-go/v7" - "github.com/redis/go-redis/v9" "github.com/zeromicro/go-zero/core/logx" "golang.org/x/sync/errgroup" "image" @@ -20,8 +19,6 @@ import ( "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/app/auth/model/mysql/query" "schisandra-album-cloud-microservices/common/constant" - "schisandra-album-cloud-microservices/common/encrypt" - storageConfig "schisandra-album-cloud-microservices/common/storage/config" "strconv" "time" ) @@ -76,7 +73,7 @@ func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) ( for _, img := range req.Images { img := img // 确保每个协程有独立的 img 参数副本 g.Go(func() error { - return l.uploadImageAndRecord(tx, uid, album, img, req) + return l.uploadImageAndRecord(tx, uid, album, img) }) } @@ -101,8 +98,6 @@ func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) ( ValidityPeriod: int64(duration), ExpireTime: expiryTime, ImageCount: int64(len(req.Images)), - Provider: req.Provider, - Bucket: req.Bucket, } err = tx.ScaStorageShare.Create(&storageShare) if err != nil { @@ -130,33 +125,30 @@ func (l *UploadShareImageLogic) UploadShareImage(req *types.ShareImageRequest) ( return storageShare.InviteCode, nil } -func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid string, album model.ScaStorageAlbum, img types.ShareImageMeta, req *types.ShareImageRequest) error { +func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid string, album model.ScaStorageAlbum, img types.ShareImageMeta) error { - // 上传原始图片到用户的存储桶 + // 上传原始图片到存储桶 originImage, err := base64.StdEncoding.DecodeString(img.OriginImage) if err != nil { return fmt.Errorf("base64 decode failed: %v", err) } originObjectKey := path.Join( - "share_space", uid, time.Now().Format("2006/01"), fmt.Sprintf("%s_%s%s", img.FileName, kgo.SimpleUuid(), filepath.Ext(img.FileName)), ) - // 获取存储服务 - ossConfig, err := l.getOssConfigFromCacheOrDb(constant.UserOssConfigPrefix+uid+":"+req.Provider, uid, req.Provider) + _, err = l.svcCtx.MinioClient.PutObject( + l.ctx, + constant.ShareImagesBucketName, + originObjectKey, + bytes.NewReader(originImage), + int64(len(originImage)), + minio.PutObjectOptions{ + ContentType: "image/jpeg", + }, + ) if err != nil { - return err - } - service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig) - if err != nil { - return errors.New("get storage failed") - } - _, err = service.UploadFileSimple(l.ctx, ossConfig.BucketName, originObjectKey, bytes.NewReader(originImage), map[string]string{ - "Content-Type": img.FileType, - }) - if err != nil { - logx.Errorf("Failed to upload object to storage: %v", err) + logx.Errorf("Failed to upload object to MinIO: %v", err) return err } @@ -169,8 +161,6 @@ func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid stri // 记录原始图片信息 imageRecord := model.ScaStorageInfo{ UserID: uid, - Provider: req.Provider, - Bucket: req.Bucket, Path: originObjectKey, FileName: img.FileName, FileSize: strconv.Itoa(size), @@ -197,14 +187,7 @@ func (l *UploadShareImageLogic) uploadImageAndRecord(tx *query.QueryTx, uid stri l.classifyFile(img.FileType), fmt.Sprintf("%s_%s.jpg", time.Now().Format("20060102150405"), kgo.SimpleUuid()), ) - exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName) - if err != nil || !exists { - err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) - if err != nil { - logx.Errorf("Failed to create MinIO bucket: %v", err) - return err - } - } + _, err = l.svcCtx.MinioClient.PutObject( l.ctx, constant.ThumbnailBucketName, @@ -257,66 +240,6 @@ func (l *UploadShareImageLogic) GetImageInfo(base64Str string) (width, height in return imgCfg.Width, imgCfg.Height, size, nil } -// 提取解密操作为函数 -func (l *UploadShareImageLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) { - accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key) - if err != nil { - return nil, errors.New("decrypt access key failed") - } - secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key) - if err != nil { - return nil, errors.New("decrypt secret key failed") - } - return &storageConfig.StorageConfig{ - Provider: config.Provider, - Endpoint: config.Endpoint, - AccessKey: accessKey, - SecretKey: secretKey, - BucketName: config.Bucket, - Region: config.Region, - }, nil -} - -// 从缓存或数据库中获取 OSS 配置 -func (l *UploadShareImageLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) { - result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result() - if err != nil && !errors.Is(err, redis.Nil) { - return nil, errors.New("get oss config failed") - } - - var ossConfig *storageConfig.StorageConfig - if result != "" { - var redisOssConfig model.ScaStorageConfig - if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil { - return nil, errors.New("unmarshal oss config failed") - } - return l.decryptConfig(&redisOssConfig) - } - - // 缓存未命中,从数据库中加载 - scaOssConfig := l.svcCtx.DB.ScaStorageConfig - dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First() - if err != nil { - return nil, err - } - - // 缓存数据库配置 - ossConfig, err = l.decryptConfig(dbOssConfig) - if err != nil { - return nil, err - } - marshalData, err := json.Marshal(dbOssConfig) - if err != nil { - return nil, errors.New("marshal oss config failed") - } - err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err() - if err != nil { - return nil, errors.New("set oss config failed") - } - - return ossConfig, nil -} - // GenerateExpiryTime 函数接受当前时间和有效期(天为单位),返回过期时间 func (l *UploadShareImageLogic) GenerateExpiryTime(currentTime time.Time, durationInDays int) time.Time { // 创建一个持续时间对象 diff --git a/app/auth/api/internal/logic/storage/download_album_logic.go b/app/auth/api/internal/logic/storage/download_album_logic.go index 6d70b43..6358bc4 100644 --- a/app/auth/api/internal/logic/storage/download_album_logic.go +++ b/app/auth/api/internal/logic/storage/download_album_logic.go @@ -24,7 +24,7 @@ func NewDownloadAlbumLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Dow } func (l *DownloadAlbumLogic) DownloadAlbum(req *types.DownloadAlbumRequest) (resp string, err error) { - // todo: add your logic here and delete this line + // todo: download album logic return } diff --git a/app/auth/api/internal/logic/storage/get_album_detail_logic.go b/app/auth/api/internal/logic/storage/get_album_detail_logic.go index 5baf775..5a335c4 100644 --- a/app/auth/api/internal/logic/storage/get_album_detail_logic.go +++ b/app/auth/api/internal/logic/storage/get_album_detail_logic.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "github.com/redis/go-redis/v9" + "gorm.io/gen" "math/rand" "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" @@ -63,6 +64,14 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest) // 数据库查询文件信息列表 var storageInfoQuery query.IScaStorageInfoDo var storageInfoList []types.FileInfoResult + var queryCondition []gen.Condition + queryCondition = append(queryCondition, storageInfo.UserID.Eq(uid)) + queryCondition = append(queryCondition, storageInfo.AlbumID.Eq(req.ID)) + // 类型筛选 1 是分享类型 + if req.Type != constant.AlbumTypeShared { + queryCondition = append(queryCondition, storageInfo.Provider.Eq(req.Provider)) + queryCondition = append(queryCondition, storageInfo.Bucket.Eq(req.Bucket)) + } storageInfoQuery = storageInfo.Select( storageInfo.ID, @@ -74,11 +83,7 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest) storageThumb.ThumbH, storageThumb.ThumbSize). LeftJoin(storageThumb, storageInfo.ID.EqCol(storageThumb.InfoID)). - Where( - storageInfo.UserID.Eq(uid), - storageInfo.Provider.Eq(req.Provider), - storageInfo.Bucket.Eq(req.Bucket), - storageInfo.AlbumID.Eq(req.ID)). + Where(queryCondition...). Order(storageInfo.CreatedAt.Desc()) err = storageInfoQuery.Scan(&storageInfoList) if err != nil { @@ -103,24 +108,41 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest) // 按日期进行分组 var wg sync.WaitGroup groupedImages := sync.Map{} - + reqParams := make(url.Values) for _, dbFileInfo := range storageInfoList { wg.Add(1) go func(dbFileInfo *types.FileInfoResult) { defer wg.Done() weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) - if err != nil { - logx.Error(err) - return - } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) - if err != nil { - logx.Error(err) - return + + var thumbnailUrl string + var originalUrl string + + if req.Type == constant.AlbumTypeShared { + minioOriginalUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ShareImagesBucketName, dbFileInfo.Path, 30*time.Minute, reqParams) + originalUrl = minioOriginalUrl.String() + if err != nil { + return + } + minioThumbnailUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, 30*time.Minute, reqParams) + thumbnailUrl = minioThumbnailUrl.String() + if err != nil { + return + } + } else { + thumbnailUrl, err = service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) + if err != nil { + logx.Error(err) + return + } + originalUrl, err = service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) + if err != nil { + logx.Error(err) + return + } } + // 使用 Load 或 Store 确保原子操作 value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{}) images := value.([]types.ImageMeta) @@ -128,8 +150,8 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest) images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), - URL: url, + Thumbnail: thumbnailUrl, + URL: originalUrl, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"), diff --git a/app/auth/api/internal/logic/storage/get_album_list_logic.go b/app/auth/api/internal/logic/storage/get_album_list_logic.go index 66ad52c..866f268 100644 --- a/app/auth/api/internal/logic/storage/get_album_list_logic.go +++ b/app/auth/api/internal/logic/storage/get_album_list_logic.go @@ -39,10 +39,10 @@ func (l *GetAlbumListLogic) GetAlbumList(req *types.AlbumListRequest) (resp *typ orderConditions = append(orderConditions, storageAlbum.AlbumName.Desc()) } var typeConditions []gen.Condition + typeConditions = append(typeConditions, storageAlbum.UserID.Eq(uid)) if req.Type != -1 { // 获取全部相册 typeConditions = append(typeConditions, storageAlbum.AlbumType.Eq(req.Type)) - typeConditions = append(typeConditions, storageAlbum.UserID.Eq(uid)) } albums, err := storageAlbum.Where( typeConditions...). diff --git a/app/auth/api/internal/logic/storage/get_delete_record_logic.go b/app/auth/api/internal/logic/storage/get_delete_record_logic.go index 9522773..1e9d06a 100644 --- a/app/auth/api/internal/logic/storage/get_delete_record_logic.go +++ b/app/auth/api/internal/logic/storage/get_delete_record_logic.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/redis/go-redis/v9" "math/rand" - "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/common/constant" "schisandra-album-cloud-microservices/common/encrypt" @@ -108,13 +107,12 @@ func (l *GetDeleteRecordLogic) GetDeleteRecord(req *types.QueryDeleteRecordReque defer wg.Done() weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) if err != nil { logx.Error(err) return } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) + url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) if err != nil { logx.Error(err) return @@ -126,7 +124,7 @@ func (l *GetDeleteRecordLogic) GetDeleteRecord(req *types.QueryDeleteRecordReque images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), + Thumbnail: thumbnailUrl, URL: url, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, diff --git a/app/auth/api/internal/logic/storage/get_face_detail_list_logic.go b/app/auth/api/internal/logic/storage/get_face_detail_list_logic.go index b72ebdb..348218a 100644 --- a/app/auth/api/internal/logic/storage/get_face_detail_list_logic.go +++ b/app/auth/api/internal/logic/storage/get_face_detail_list_logic.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/redis/go-redis/v9" "math/rand" - "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/common/constant" "schisandra-album-cloud-microservices/common/encrypt" @@ -106,13 +105,13 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ defer wg.Done() weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) + + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) if err != nil { logx.Error(err) return } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) + url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) if err != nil { logx.Error(err) return @@ -125,7 +124,7 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), + Thumbnail: thumbnailUrl, URL: url, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, diff --git a/app/auth/api/internal/logic/storage/query_all_image_list_logic.go b/app/auth/api/internal/logic/storage/query_all_image_list_logic.go index 7a0a745..e3fcb7f 100644 --- a/app/auth/api/internal/logic/storage/query_all_image_list_logic.go +++ b/app/auth/api/internal/logic/storage/query_all_image_list_logic.go @@ -11,7 +11,6 @@ import ( "golang.org/x/sync/semaphore" "gorm.io/gen" "math/rand" - "net/url" "schisandra-album-cloud-microservices/app/auth/api/internal/svc" "schisandra-album-cloud-microservices/app/auth/api/internal/types" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" @@ -135,13 +134,12 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques defer sem.Release(1) weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) if err != nil { logx.Error(err) return err } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) + url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) if err != nil { logx.Error(err) return err @@ -153,7 +151,7 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), + Thumbnail: thumbnailUrl, URL: url, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, diff --git a/app/auth/api/internal/logic/storage/query_location_detail_list_logic.go b/app/auth/api/internal/logic/storage/query_location_detail_list_logic.go index 28c6d4e..b6d88ac 100644 --- a/app/auth/api/internal/logic/storage/query_location_detail_list_logic.go +++ b/app/auth/api/internal/logic/storage/query_location_detail_list_logic.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/redis/go-redis/v9" "math/rand" - "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/app/auth/model/mysql/query" "schisandra-album-cloud-microservices/common/constant" @@ -112,13 +111,12 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati defer wg.Done() weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) if err != nil { logx.Error(err) return } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) + url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) if err != nil { logx.Error(err) return @@ -130,7 +128,7 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), + Thumbnail: thumbnailUrl, URL: url, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, diff --git a/app/auth/api/internal/logic/storage/query_location_image_list_logic.go b/app/auth/api/internal/logic/storage/query_location_image_list_logic.go index 83cde21..477eb57 100644 --- a/app/auth/api/internal/logic/storage/query_location_image_list_logic.go +++ b/app/auth/api/internal/logic/storage/query_location_image_list_logic.go @@ -2,12 +2,16 @@ package storage import ( "context" + "encoding/json" "errors" "fmt" - "net/url" + "github.com/redis/go-redis/v9" "schisandra-album-cloud-microservices/app/auth/api/internal/svc" "schisandra-album-cloud-microservices/app/auth/api/internal/types" + "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/common/constant" + "schisandra-album-cloud-microservices/common/encrypt" + storageConfig "schisandra-album-cloud-microservices/common/storage/config" "time" "github.com/zeromicro/go-zero/core/logx" @@ -54,6 +58,18 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location return nil, err } + // 加载用户oss配置信息 + cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider + ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider) + if err != nil { + return nil, err + } + + service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig) + if err != nil { + return nil, errors.New("get storage failed") + } + locationMap := make(map[string][]types.LocationMeta) for _, loc := range locations { @@ -68,16 +84,16 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location if city == "" { city = loc.Country } - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, loc.CoverImage, 15*time.Minute, reqParams) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, loc.CoverImage, time.Minute*30) if err != nil { - return nil, errors.New("get presigned url failed") + logx.Error(err) + return nil, err } locationMeta := types.LocationMeta{ ID: loc.ID, City: city, Total: loc.Total, - CoverImage: presignedUrl.String(), + CoverImage: thumbnailUrl, } locationMap[locationKey] = append(locationMap[locationKey], locationMeta) } @@ -93,3 +109,63 @@ func (l *QueryLocationImageListLogic) QueryLocationImageList(req *types.Location return &types.LocationListResponse{Records: locationListData}, nil } + +// 提取解密操作为函数 +func (l *QueryLocationImageListLogic) decryptConfig(config *model.ScaStorageConfig) (*storageConfig.StorageConfig, error) { + accessKey, err := encrypt.Decrypt(config.AccessKey, l.svcCtx.Config.Encrypt.Key) + if err != nil { + return nil, errors.New("decrypt access key failed") + } + secretKey, err := encrypt.Decrypt(config.SecretKey, l.svcCtx.Config.Encrypt.Key) + if err != nil { + return nil, errors.New("decrypt secret key failed") + } + return &storageConfig.StorageConfig{ + Provider: config.Provider, + Endpoint: config.Endpoint, + AccessKey: accessKey, + SecretKey: secretKey, + BucketName: config.Bucket, + Region: config.Region, + }, nil +} + +// 从缓存或数据库中获取 OSS 配置 +func (l *QueryLocationImageListLogic) getOssConfigFromCacheOrDb(cacheKey, uid, provider string) (*storageConfig.StorageConfig, error) { + result, err := l.svcCtx.RedisClient.Get(l.ctx, cacheKey).Result() + if err != nil && !errors.Is(err, redis.Nil) { + return nil, errors.New("get oss config failed") + } + + var ossConfig *storageConfig.StorageConfig + if result != "" { + var redisOssConfig model.ScaStorageConfig + if err = json.Unmarshal([]byte(result), &redisOssConfig); err != nil { + return nil, errors.New("unmarshal oss config failed") + } + return l.decryptConfig(&redisOssConfig) + } + + // 缓存未命中,从数据库中加载 + scaOssConfig := l.svcCtx.DB.ScaStorageConfig + dbOssConfig, err := scaOssConfig.Where(scaOssConfig.UserID.Eq(uid), scaOssConfig.Provider.Eq(provider)).First() + if err != nil { + return nil, err + } + + // 缓存数据库配置 + ossConfig, err = l.decryptConfig(dbOssConfig) + if err != nil { + return nil, err + } + marshalData, err := json.Marshal(dbOssConfig) + if err != nil { + return nil, errors.New("marshal oss config failed") + } + err = l.svcCtx.RedisClient.Set(l.ctx, cacheKey, marshalData, 0).Err() + if err != nil { + return nil, errors.New("set oss config failed") + } + + return ossConfig, nil +} diff --git a/app/auth/api/internal/logic/storage/query_recent_image_list_logic.go b/app/auth/api/internal/logic/storage/query_recent_image_list_logic.go index 39146bc..281ab0c 100644 --- a/app/auth/api/internal/logic/storage/query_recent_image_list_logic.go +++ b/app/auth/api/internal/logic/storage/query_recent_image_list_logic.go @@ -9,7 +9,6 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" "math/rand" - "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/common/constant" "schisandra-album-cloud-microservices/common/encrypt" @@ -119,13 +118,12 @@ func (l *QueryRecentImageListLogic) QueryRecentImageList(req *types.RecentListRe defer sem.Release(1) weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) if err != nil { logx.Error(err) return err } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) + url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) if err != nil { logx.Error(err) return err @@ -137,7 +135,7 @@ func (l *QueryRecentImageListLogic) QueryRecentImageList(req *types.RecentListRe images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), + Thumbnail: thumbnailUrl, URL: url, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, diff --git a/app/auth/api/internal/logic/storage/query_thing_detail_list_logic.go b/app/auth/api/internal/logic/storage/query_thing_detail_list_logic.go index 2c289ad..6047b38 100644 --- a/app/auth/api/internal/logic/storage/query_thing_detail_list_logic.go +++ b/app/auth/api/internal/logic/storage/query_thing_detail_list_logic.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/redis/go-redis/v9" "math/rand" - "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/app/auth/model/mysql/query" "schisandra-album-cloud-microservices/common/constant" @@ -112,13 +111,12 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL defer wg.Done() weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()] date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday) - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, dbFileInfo.ThumbPath, time.Hour*24*7, reqParams) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.ThumbPath, time.Minute*30) if err != nil { logx.Error(err) return } - url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Hour*24*7) + url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30) if err != nil { logx.Error(err) return @@ -130,7 +128,7 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL images = append(images, types.ImageMeta{ ID: dbFileInfo.ID, FileName: dbFileInfo.FileName, - Thumbnail: presignedUrl.String(), + Thumbnail: thumbnailUrl, URL: url, Width: dbFileInfo.ThumbW, Height: dbFileInfo.ThumbH, diff --git a/app/auth/api/internal/logic/storage/query_thing_image_list_logic.go b/app/auth/api/internal/logic/storage/query_thing_image_list_logic.go index 363e938..4b4b534 100644 --- a/app/auth/api/internal/logic/storage/query_thing_image_list_logic.go +++ b/app/auth/api/internal/logic/storage/query_thing_image_list_logic.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "github.com/redis/go-redis/v9" - "net/url" "schisandra-album-cloud-microservices/app/auth/model/mysql/model" "schisandra-album-cloud-microservices/common/constant" "schisandra-album-cloud-microservices/common/encrypt" @@ -65,16 +64,16 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque } // 加载用户oss配置信息 - //cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider - //ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider) - //if err != nil { - // return nil, err - //} - // - //service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig) - //if err != nil { - // return nil, errors.New("get storage failed") - //} + cacheOssConfigKey := constant.UserOssConfigPrefix + uid + ":" + req.Provider + ossConfig, err := l.getOssConfigFromCacheOrDb(cacheOssConfigKey, uid, req.Provider) + if err != nil { + return nil, err + } + + service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig) + if err != nil { + return nil, errors.New("get storage failed") + } categoryMap := sync.Map{} tagCountMap := sync.Map{} @@ -97,11 +96,12 @@ func (l *QueryThingImageListLogic) QueryThingImageList(req *types.ThingListReque // 为每个 Tag 存储封面图片路径 if _, exists := tagCoverMap.Load(tagKey); !exists { // 使用服务生成预签名 URL - reqParams := make(url.Values) - presignedUrl, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, info.ThumbPath, time.Hour*24*7, reqParams) - if err == nil { - tagCoverMap.Store(tagKey, presignedUrl.String()) + thumbnailUrl, err := service.PresignedURL(l.ctx, ossConfig.BucketName, info.ThumbPath, time.Minute*30) + if err != nil { + logx.Error(err) + return nil, errors.New("get presigned url failed") } + tagCoverMap.Store(tagKey, thumbnailUrl) } } diff --git a/app/auth/api/internal/logic/storage/set_storage_config_logic.go b/app/auth/api/internal/logic/storage/set_storage_config_logic.go index 9cef2b7..463f536 100644 --- a/app/auth/api/internal/logic/storage/set_storage_config_logic.go +++ b/app/auth/api/internal/logic/storage/set_storage_config_logic.go @@ -46,6 +46,7 @@ func (l *SetStorageConfigLogic) SetStorageConfig(req *types.StorageConfigRequest AccessKey: accessKey, SecretKey: secretKey, Region: req.Region, + Capacity: req.Capacity, } err = l.svcCtx.DB.ScaStorageConfig.Create(ossConfig) if err != nil { diff --git a/app/auth/api/internal/logic/storage/share_album_logic.go b/app/auth/api/internal/logic/storage/share_album_logic.go index 7f30d82..67d2625 100644 --- a/app/auth/api/internal/logic/storage/share_album_logic.go +++ b/app/auth/api/internal/logic/storage/share_album_logic.go @@ -87,8 +87,6 @@ func (l *ShareAlbumLogic) ShareAlbum(req *types.ShareAlbumRequest) (resp string, AccessPassword: req.AccessPassword, VisitLimit: req.AccessLimit, ImageCount: imageCount, - Provider: req.Provider, - Bucket: req.Bucket, Status: 0, } err = storageShare.Create(storageShareInfo) diff --git a/app/auth/api/internal/logic/storage/upload_file_logic.go b/app/auth/api/internal/logic/storage/upload_file_logic.go index 9a795ba..c8fea8a 100644 --- a/app/auth/api/internal/logic/storage/upload_file_logic.go +++ b/app/auth/api/internal/logic/storage/upload_file_logic.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "github.com/ccpwcn/kgo" - "github.com/minio/minio-go/v7" "github.com/redis/go-redis/v9" "github.com/zeromicro/go-zero/core/logx" "golang.org/x/sync/errgroup" @@ -79,9 +78,9 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) { // 使用 `errgroup.Group` 处理并发任务 var ( - faceId int64 - filePath string - minioFilePath string + faceId int64 + filePath string + thumbPath string ) g, ctx := errgroup.WithContext(context.Background()) // 创建信号量,限制最大并发上传数(比如最多同时 5 个任务) @@ -119,26 +118,12 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) { Closer: io.NopCloser(nil), } - fileUrl, err := l.uploadFileToOSS(uid, header, fileReader, result) + fileUrl, thumbUrl, err := l.uploadFileToOSS(uid, header, fileReader, thumbnail, result) if err != nil { return err } filePath = fileUrl - return nil - }) - - // 上传缩略图到 MinIO - g.Go(func() error { - if err := sem.Acquire(ctx, 1); err != nil { - return err - } - defer sem.Release(1) - - path, err := l.uploadFileToMinio(uid, header, thumbnail, result) - if err != nil { - return err - } - minioFilePath = path + thumbPath = thumbUrl return nil }) @@ -149,11 +134,11 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) { fileUploadMessage := &types.FileUploadMessage{ UID: uid, - Data: result, + Result: result, FaceID: faceId, FileHeader: header, FilePath: filePath, - ThumbPath: minioFilePath, + ThumbPath: thumbPath, } // 转换为 JSON messageData, err := json.Marshal(fileUploadMessage) @@ -205,19 +190,19 @@ func (l *UploadFileLogic) parseImageInfoResult(r *http.Request) (types.File, err } // 上传文件到 OSS -func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, error) { +func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, thumbnail multipart.File, result types.File) (string, string, error) { cacheKey := constant.UserOssConfigPrefix + uid + ":" + result.Provider ossConfig, err := l.getOssConfigFromCacheOrDb(cacheKey, uid, result.Provider) if err != nil { - return "", errors.New("get oss config failed") + return "", "", errors.New("get oss config failed") } service, err := l.svcCtx.StorageManager.GetStorage(uid, ossConfig) if err != nil { - return "", errors.New("get storage failed") + return "", "", errors.New("get storage failed") } objectKey := path.Join( - "image_space", + constant.ImageSpace, uid, time.Now().Format("2006/01"), // 按年/月划分目录 l.classifyFile(result.FileType, result.IsScreenshot), @@ -228,52 +213,62 @@ func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHead "Content-Type": header.Header.Get("Content-Type"), }) if err != nil { - return "", errors.New("upload file failed") + return "", "", errors.New("upload file failed") } - //url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, objectKey, time.Hour*24*7) - //if err != nil { - // return "", "", errors.New("presigned url failed") - //} - return objectKey, nil -} - -func (l *UploadFileLogic) uploadFileToMinio(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, error) { - objectKey := path.Join( + // 上传缩略图 + thumbObjectKey := path.Join( + constant.ThumbnailSpace, uid, time.Now().Format("2006/01"), // 按年/月划分目录 l.classifyFile(result.FileType, result.IsScreenshot), fmt.Sprintf("%s_%s%s", strings.TrimSuffix(header.Filename, filepath.Ext(header.Filename)), kgo.SimpleUuid(), filepath.Ext(header.Filename)), ) - exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName) - if err != nil || !exists { - err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) - if err != nil { - logx.Errorf("Failed to create MinIO bucket: %v", err) - return "", err - } - } - // 上传到MinIO - _, err = l.svcCtx.MinioClient.PutObject( - l.ctx, - constant.ThumbnailBucketName, - objectKey, - file, - int64(result.ThumbSize), - minio.PutObjectOptions{ - ContentType: result.FileType, - }, - ) + _, err = service.UploadFileSimple(l.ctx, ossConfig.BucketName, thumbObjectKey, thumbnail, map[string]string{ + "Content-Type": header.Header.Get("Content-Type"), + }) if err != nil { - return "", err + return "", "", errors.New("upload thumbnail file failed") } - //reqParams := make(url.Values) - //presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, objectKey, time.Hour*24*7, reqParams) - //if err != nil { - // return "", "", err - //} - return objectKey, nil + return objectKey, thumbObjectKey, nil } +//func (l *UploadFileLogic) uploadFileToMinio(uid string, header *multipart.FileHeader, file multipart.File, result types.File) (string, error) { +// objectKey := path.Join( +// uid, +// time.Now().Format("2006/01"), // 按年/月划分目录 +// l.classifyFile(result.FileType, result.IsScreenshot), +// fmt.Sprintf("%s_%s%s", strings.TrimSuffix(header.Filename, filepath.Ext(header.Filename)), kgo.SimpleUuid(), filepath.Ext(header.Filename)), +// ) +// exists, err := l.svcCtx.MinioClient.BucketExists(l.ctx, constant.ThumbnailBucketName) +// if err != nil || !exists { +// err = l.svcCtx.MinioClient.MakeBucket(l.ctx, constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) +// if err != nil { +// logx.Errorf("Failed to create MinIO bucket: %v", err) +// return "", err +// } +// } +// // 上传到MinIO +// _, err = l.svcCtx.MinioClient.PutObject( +// l.ctx, +// constant.ThumbnailBucketName, +// objectKey, +// file, +// int64(result.ThumbSize), +// minio.PutObjectOptions{ +// ContentType: result.FileType, +// }, +// ) +// if err != nil { +// return "", err +// } +// //reqParams := make(url.Values) +// //presignedURL, err := l.svcCtx.MinioClient.PresignedGetObject(l.ctx, constant.ThumbnailBucketName, objectKey, time.Hour*24*7, reqParams) +// //if err != nil { +// // return "", "", err +// //} +// return objectKey, nil +//} + // 提取解密操作为函数 func (l *UploadFileLogic) decryptConfig(dbConfig *model.ScaStorageConfig) (*config.StorageConfig, error) { accessKey, err := encrypt.Decrypt(dbConfig.AccessKey, l.svcCtx.Config.Encrypt.Key) @@ -352,14 +347,15 @@ func (l *UploadFileLogic) classifyFile(mimeType string, isScreenshot bool) strin "video/x-matroska": "video", } + // 如果isScreenshot为true,则返回"screenshot" + if isScreenshot { + return "screenshot" + } + // 根据MIME类型从map中获取分类 if classification, exists := typeMap[mimeType]; exists { return classification } - // 如果isScreenshot为true,则返回"screenshot" - if isScreenshot { - return "screenshot" - } return "unknown" } diff --git a/app/auth/api/internal/mq/image_process_consumer.go b/app/auth/api/internal/mq/image_process_consumer.go index 7ed09c5..be28ff5 100644 --- a/app/auth/api/internal/mq/image_process_consumer.go +++ b/app/auth/api/internal/mq/image_process_consumer.go @@ -49,36 +49,28 @@ func (c *NsqImageProcessConsumer) HandleMessage(msg *nsq.Message) error { } // 根据 GPS 信息获取地理位置信息 - country, province, city, err := c.getGeoLocation(message.Data.Latitude, message.Data.Longitude) + country, province, city, err := c.getGeoLocation(message.Result.Latitude, message.Result.Longitude) if err != nil { return err } // 将地址信息保存到数据库 - locationId, err := c.saveFileLocationInfoToDB(message.UID, message.Data.Latitude, message.Data.Longitude, country, province, city, message.ThumbPath) + locationId, err := c.saveFileLocationInfoToDB(message.UID, message.Result.Latitude, message.Result.Longitude, country, province, city, message.ThumbPath) if err != nil { return err } // 将文件信息存入数据库 - storageId, err := c.saveFileInfoToDB(message.UID, message.Data.Bucket, message.Data.Provider, message.FileHeader, message.Data, message.FaceID, message.FilePath, locationId, message.Data.AlbumId) + storageId, err := c.saveFileInfoToDB(message.UID, message.Result.Bucket, message.Result.Provider, message.FileHeader, message.Result, message.FaceID, message.FilePath, locationId, message.Result.AlbumId) if err != nil { return err } - err = c.saveFileThumbnailInfoToDB(message.UID, message.ThumbPath, message.Data.ThumbW, message.Data.ThumbH, message.Data.ThumbSize, storageId) - + err = c.saveFileThumbnailInfoToDB(message.UID, message.ThumbPath, message.Result.ThumbW, message.Result.ThumbH, message.Result.ThumbSize, storageId) if err != nil { return err } - // 删除缓存 c.afterImageUpload(message.UID) - // redis 保存最近7天上传的文件列表 - //err = c.saveRecentFileList(message.UID, message.Thumbnail, message.URL, storageId, message.Data, message.FileHeader.Filename) - //if err != nil { - // return err - //} - return nil } @@ -166,32 +158,6 @@ func (c *NsqImageProcessConsumer) classifyFile(mimeType string, isScreenshot boo return "unknown" } -//// 保存最近7天上传的文件列表 -//func (c *NsqImageProcessConsumer) saveRecentFileList(uid, thumbnail, url string, id int64, result types.File, filename string) error { -// -// redisKey := constant.ImageRecentPrefix + uid + ":" + strconv.FormatInt(id, 10) -// imageMeta := types.ImageMeta{ -// ID: id, -// URL: url, -// FileName: filename, -// Width: result.ThumbW, -// Height: result.ThumbH, -// Thumbnail: thumbnail, -// CreatedAt: time.Now().Format("2006-01-02 15:04:05"), -// } -// marshal, err := json.Marshal(imageMeta) -// if err != nil { -// logx.Error(err) -// return errors.New("marshal image meta failed") -// } -// err = c.svcCtx.RedisClient.Set(c.ctx, redisKey, marshal, time.Hour*24*7).Err() -// if err != nil { -// logx.Error(err) -// return errors.New("save recent file list failed") -// } -// return nil -//} - // 提取解密操作为函数 func (c *NsqImageProcessConsumer) decryptConfig(dbConfig *model.ScaStorageConfig) (*config.StorageConfig, error) { accessKey, err := encrypt.Decrypt(dbConfig.AccessKey, c.svcCtx.Config.Encrypt.Key) diff --git a/app/auth/api/internal/types/file_types.go b/app/auth/api/internal/types/file_types.go index 9d3b3e9..eae8359 100644 --- a/app/auth/api/internal/types/file_types.go +++ b/app/auth/api/internal/types/file_types.go @@ -29,7 +29,7 @@ type File struct { type FileUploadMessage struct { FaceID int64 `json:"face_id"` FileHeader *multipart.FileHeader `json:"fileHeader"` - Data File `json:"data"` + Result File `json:"result"` UID string `json:"uid"` FilePath string `json:"filePath"` URL string `json:"url"` diff --git a/app/auth/api/internal/types/types.go b/app/auth/api/internal/types/types.go index 47b616a..7659414 100644 --- a/app/auth/api/internal/types/types.go +++ b/app/auth/api/internal/types/types.go @@ -35,6 +35,7 @@ type AlbumDetailListRequest struct { ID int64 `json:"id"` Provider string `json:"provider"` Bucket string `json:"bucket"` + Type int64 `json:"type"` } type AlbumDetailListResponse struct { @@ -298,7 +299,7 @@ type QueryShareImageRequest struct { } type QueryShareImageResponse struct { - Records []ShareImageListMeta `json:"records"` + Records []AllImageDetail `json:"records"` } type QueryShareInfoRequest struct { @@ -371,17 +372,6 @@ type ShareAlbumRequest struct { Bucket string `json:"bucket"` } -type ShareImageListMeta struct { - ID int64 `json:"id"` - FileName string `json:"file_name"` - URL string `json:"url"` - Thumbnail string `json:"thumbnail"` - Width float64 `json:"width"` - Height float64 `json:"height"` - ThumbSize float64 `json:"thumb_size"` - CreatedAt string `json:"created_at"` -} - type ShareImageMeta struct { FileName string `json:"file_name"` OriginImage string `json:"origin_image"` @@ -397,8 +387,6 @@ type ShareImageRequest struct { ExpireDate string `json:"expire_date"` AccessLimit int64 `json:"access_limit,omitempty"` AccessPassword string `json:"access_password,omitempty"` - Provider string `json:"provider"` - Bucket string `json:"bucket"` Images []ShareImageMeta `json:"images"` } @@ -480,6 +468,7 @@ type StorageConfigRequest struct { Endpoint string `json:"endpoint"` Bucket string `json:"bucket"` Region string `json:"region"` + Capacity int64 `json:"capacity"` } type StorageListResponse struct { diff --git a/app/auth/model/mysql/model/sca_storage_share.gen.go b/app/auth/model/mysql/model/sca_storage_share.gen.go index d9abbda..20f878a 100644 --- a/app/auth/model/mysql/model/sca_storage_share.gen.go +++ b/app/auth/model/mysql/model/sca_storage_share.gen.go @@ -18,8 +18,6 @@ type ScaStorageShare 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 AlbumID int64 `gorm:"column:album_id;type:bigint(20);comment:相册ID" json:"album_id"` // 相册ID - Provider string `gorm:"column:provider;type:varchar(50);comment:存储商" json:"provider"` // 存储商 - Bucket string `gorm:"column:bucket;type:varchar(50);comment:存储桶" json:"bucket"` // 存储桶 InviteCode string `gorm:"column:invite_code;type:varchar(50);comment:邀请码(用于访问分享链接)" json:"invite_code"` // 邀请码(用于访问分享链接) ExpireTime time.Time `gorm:"column:expire_time;type:datetime;comment:过期时间" json:"expire_time"` // 过期时间 ValidityPeriod int64 `gorm:"column:validity_period;type:int(11);comment:有效期" json:"validity_period"` // 有效期 diff --git a/app/auth/model/mysql/mysql.go b/app/auth/model/mysql/mysql.go index 40f4a7d..3f55404 100644 --- a/app/auth/model/mysql/mysql.go +++ b/app/auth/model/mysql/mysql.go @@ -24,7 +24,7 @@ func NewMySQL(url string, maxOpenConn int, maxIdleConn int, client *redis.Client log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{ SlowThreshold: time.Second, // 慢sql日志 - LogLevel: logger.Info, // 级别 + LogLevel: logger.Warn, // 级别 Colorful: true, // 颜色 IgnoreRecordNotFoundError: true, // 忽略RecordNotFoundError ParameterizedQueries: true, // 格式化SQL语句 diff --git a/app/auth/model/mysql/query/sca_storage_share.gen.go b/app/auth/model/mysql/query/sca_storage_share.gen.go index e1b07ca..ac7611c 100644 --- a/app/auth/model/mysql/query/sca_storage_share.gen.go +++ b/app/auth/model/mysql/query/sca_storage_share.gen.go @@ -30,8 +30,6 @@ func newScaStorageShare(db *gorm.DB, opts ...gen.DOOption) scaStorageShare { _scaStorageShare.ID = field.NewInt64(tableName, "id") _scaStorageShare.UserID = field.NewString(tableName, "user_id") _scaStorageShare.AlbumID = field.NewInt64(tableName, "album_id") - _scaStorageShare.Provider = field.NewString(tableName, "provider") - _scaStorageShare.Bucket = field.NewString(tableName, "bucket") _scaStorageShare.InviteCode = field.NewString(tableName, "invite_code") _scaStorageShare.ExpireTime = field.NewTime(tableName, "expire_time") _scaStorageShare.ValidityPeriod = field.NewInt64(tableName, "validity_period") @@ -57,8 +55,6 @@ type scaStorageShare struct { ID field.Int64 // 主键 UserID field.String // 用户ID AlbumID field.Int64 // 相册ID - Provider field.String // 存储商 - Bucket field.String // 存储桶 InviteCode field.String // 邀请码(用于访问分享链接) ExpireTime field.Time // 过期时间 ValidityPeriod field.Int64 // 有效期 @@ -89,8 +85,6 @@ func (s *scaStorageShare) updateTableName(table string) *scaStorageShare { s.ID = field.NewInt64(table, "id") s.UserID = field.NewString(table, "user_id") s.AlbumID = field.NewInt64(table, "album_id") - s.Provider = field.NewString(table, "provider") - s.Bucket = field.NewString(table, "bucket") s.InviteCode = field.NewString(table, "invite_code") s.ExpireTime = field.NewTime(table, "expire_time") s.ValidityPeriod = field.NewInt64(table, "validity_period") @@ -118,12 +112,10 @@ func (s *scaStorageShare) GetFieldByName(fieldName string) (field.OrderExpr, boo } func (s *scaStorageShare) fillFieldMap() { - s.fieldMap = make(map[string]field.Expr, 16) + s.fieldMap = make(map[string]field.Expr, 14) s.fieldMap["id"] = s.ID s.fieldMap["user_id"] = s.UserID s.fieldMap["album_id"] = s.AlbumID - s.fieldMap["provider"] = s.Provider - s.fieldMap["bucket"] = s.Bucket s.fieldMap["invite_code"] = s.InviteCode s.fieldMap["expire_time"] = s.ExpireTime s.fieldMap["validity_period"] = s.ValidityPeriod diff --git a/auth.Dockerfile b/auth.Dockerfile index fe961c6..02ea94f 100644 --- a/auth.Dockerfile +++ b/auth.Dockerfile @@ -1,5 +1,5 @@ # to build this docker image: -# docker build -f auth.Dockerfile -t schisandra-auth-server . +# docker build -f auth.Dockerfile -t landaiqing/schisandra-auth-server:v1.0.0 . FROM golang:1.23.5-bullseye AS builder @@ -29,17 +29,19 @@ ENV TZ=Asia/Shanghai \ DEBIAN_FRONTEND=noninteractive RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ - sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ - apk add --no-cache tzdata libjpeg-turbo + apk add --no-cache tzdata libjpeg-turbo && \ + mkdir -p /app/api/etc WORKDIR /app COPY --from=builder /app/schisandra-auth-server . -COPY --from=builder /app/app/auth/api/etc ./api/etc - COPY --from=builder /app/app/auth/resources ./resources EXPOSE 80 CMD ["./schisandra-auth-server"] + + +# To run this docker image: +# docker run -p 80:80 -v /home/schisandra/backed/auth/etc:/app/api/etc --name schisandra-auth-server --restart=always landaiqing/schisandra-auth-server:v1.0.0 \ No newline at end of file diff --git a/common/captcha/initialize/text_captcha.go b/common/captcha/initialize/text_captcha.go index 1946501..bfad5b4 100644 --- a/common/captcha/initialize/text_captcha.go +++ b/common/captcha/initialize/text_captcha.go @@ -2,9 +2,9 @@ package initialize import ( "github.com/golang/freetype/truetype" + "github.com/wenlng/go-captcha-assets/bindata/chars" "github.com/wenlng/go-captcha-assets/resources/fonts/fzshengsksjw" "github.com/wenlng/go-captcha-assets/resources/images" - "github.com/wenlng/go-captcha-assets/sourcedata/chars" "github.com/wenlng/go-captcha/v2/base/option" "github.com/wenlng/go-captcha/v2/click" ) diff --git a/common/constant/bucket_name.go b/common/constant/bucket_name.go index bc54716..629dccc 100644 --- a/common/constant/bucket_name.go +++ b/common/constant/bucket_name.go @@ -1,8 +1,8 @@ package constant const ( - FaceBucketName = "schisandra-face-samples" - CommentImagesBucketName = "schisandra-comment-images" - ThumbnailBucketName = "schisandra-thumbnail-images" - ShareThumbnailBucketName = "schisandra-share-thumbnails" + FaceBucketName = "schisandra-face-samples" + CommentImagesBucketName = "schisandra-comment-images" + ThumbnailBucketName = "schisandra-thumbnail-images" + ShareImagesBucketName = "schisandra-share-images" ) diff --git a/common/constant/storage_space_name.go b/common/constant/storage_space_name.go new file mode 100644 index 0000000..aa2ce6c --- /dev/null +++ b/common/constant/storage_space_name.go @@ -0,0 +1,6 @@ +package constant + +const ( + ImageSpace = "image_space" + ThumbnailSpace = "thumbnail_space" +) diff --git a/common/miniox/minio.go b/common/miniox/minio.go index 9895898..4cd9ad8 100644 --- a/common/miniox/minio.go +++ b/common/miniox/minio.go @@ -1,8 +1,11 @@ package miniox import ( + "context" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" + "github.com/zeromicro/go-zero/core/logx" + "schisandra-album-cloud-microservices/common/constant" ) func NewMinio(endpoint, accessKeyID, secretAccessKey string, useSSL bool) *minio.Client { @@ -13,5 +16,38 @@ func NewMinio(endpoint, accessKeyID, secretAccessKey string, useSSL bool) *minio if err != nil { panic(err) } + // 初始化存储桶 + thumbnailBucketExists, err := client.BucketExists(context.Background(), constant.ThumbnailBucketName) + if err != nil || !thumbnailBucketExists { + err = client.MakeBucket(context.Background(), constant.ThumbnailBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) + if err != nil { + logx.Errorf("Failed to create MinIO bucket: %v", err) + panic(err) + } + } + faceBucketExists, err := client.BucketExists(context.Background(), constant.FaceBucketName) + if err != nil || !faceBucketExists { + err = client.MakeBucket(context.Background(), constant.FaceBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) + if err != nil { + logx.Errorf("Failed to create MinIO bucket: %v", err) + panic(err) + } + } + commentImagesBucketExists, err := client.BucketExists(context.Background(), constant.CommentImagesBucketName) + if err != nil || !commentImagesBucketExists { + err = client.MakeBucket(context.Background(), constant.CommentImagesBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) + if err != nil { + logx.Errorf("Failed to create MinIO bucket: %v", err) + panic(err) + } + } + shareImagesBucketExists, err := client.BucketExists(context.Background(), constant.ShareImagesBucketName) + if err != nil || !shareImagesBucketExists { + err = client.MakeBucket(context.Background(), constant.ShareImagesBucketName, minio.MakeBucketOptions{Region: "us-east-1", ObjectLocking: true}) + if err != nil { + logx.Errorf("Failed to create MinIO bucket: %v", err) + panic(err) + } + } return client } diff --git a/go.mod b/go.mod index 1b1f5ca..4edf80e 100644 --- a/go.mod +++ b/go.mod @@ -18,22 +18,22 @@ 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.86 + github.com/minio/minio-go/v7 v7.0.87 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.61 - github.com/wenlng/go-captcha-assets v1.0.1 + github.com/redis/go-redis/v9 v9.7.1 + github.com/tencentyun/cos-go-sdk-v5 v0.7.62 + github.com/wenlng/go-captcha-assets v1.0.5 github.com/wenlng/go-captcha/v2 v2.0.3 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.33.0 + golang.org/x/crypto v0.35.0 golang.org/x/sync v0.11.0 golang.org/x/text v0.22.0 google.golang.org/grpc v1.70.0 @@ -65,7 +65,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // 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 + github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect @@ -77,7 +77,7 @@ require ( github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/assert/v2 v2.2.0 // indirect - github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-sql-driver/mysql v1.9.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -88,7 +88,7 @@ require ( 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-cmp v0.7.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-20250208200701-d0013a598941 // indirect @@ -107,8 +107,8 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/karlseguin/ccache/v3 v3.0.6 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/lib/pq v1.10.7 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -129,12 +129,12 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // 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 + github.com/prometheus/client_golang v1.21.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.49.0 // indirect + github.com/quic-go/quic-go v0.50.0 // indirect github.com/refraction-networking/utls v1.6.7 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rs/xid v1.6.0 // indirect @@ -143,7 +143,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.18 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.18 // indirect go.etcd.io/etcd/client/v3 v3.5.18 // indirect - go.mongodb.org/mongo-driver v1.17.2 // indirect + go.mongodb.org/mongo-driver v1.17.3 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.34.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect @@ -160,17 +160,17 @@ 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-20250215185904-eff6e970281f // indirect + golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect golang.org/x/image v0.24.0 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/net v0.35.0 // indirect - golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/oauth2 v0.27.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.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 + google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 // 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 @@ -188,7 +188,7 @@ require ( 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.35.0 // indirect + modernc.org/sqlite v1.36.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 diff --git a/go.sum b/go.sum index 2dc479a..ed3bbb8 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -122,6 +124,8 @@ github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= +github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -158,6 +162,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -218,9 +224,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -258,6 +268,8 @@ github.com/minio/minio-go/v7 v7.0.85 h1:9psTLS/NTvC3MWoyjhjXpwcKoNbkongaCSF3PNpS github.com/minio/minio-go/v7 v7.0.85/go.mod h1:57YXpvc5l3rjPdhqNrDsvVlY0qPI6UTk1bflAe+9doY= github.com/minio/minio-go/v7 v7.0.86 h1:DcgQ0AUjLJzRH6y/HrxiZ8CXarA70PAIufXHodP4s+k= github.com/minio/minio-go/v7 v7.0.86/go.mod h1:VbfO4hYwUu3Of9WqGLBZ8vl3Hxnxo4ngxK4hzQDf4x4= +github.com/minio/minio-go/v7 v7.0.87 h1:nkr9x0u53PespfxfUqxP3UYWiE2a41gaofgNnC4Y8WQ= +github.com/minio/minio-go/v7 v7.0.87/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg= 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= @@ -315,6 +327,8 @@ github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4 github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= +github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= @@ -325,8 +339,12 @@ github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s= +github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyUo= +github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc= +github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -358,9 +376,13 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod 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.61 h1:tKNIjvsezkdtajqE887XAw1VL8Pq1HNtpc7rfgz25lA= github.com/tencentyun/cos-go-sdk-v5 v0.7.61/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0= +github.com/tencentyun/cos-go-sdk-v5 v0.7.62 h1:7SZVCc31rkvMxod8nwvG1Ko0N5npT39/s3NhpHBvs70= +github.com/tencentyun/cos-go-sdk-v5 v0.7.62/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 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-assets v1.0.5 h1:TL+31Qe/kJwcuYyU+jHedjSTZnMu1XKgktKL++lH9Js= +github.com/wenlng/go-captcha-assets v1.0.5/go.mod h1:zinRACsdYcL/S6pHgI9Iv7FKTU41d00+43pNX+b9+MM= github.com/wenlng/go-captcha/v2 v2.0.2 h1:8twz6pI6xZwPvEGFezoFX395oFso1MuOlJt/tLiv7pk= github.com/wenlng/go-captcha/v2 v2.0.2/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34= github.com/wenlng/go-captcha/v2 v2.0.3 h1:QTZ39/gVDisPSgvL9O2X2HbTuj5P/z8QsdGB/aayg9c= @@ -394,6 +416,8 @@ go.etcd.io/etcd/client/v3 v3.5.18/go.mod h1:kmemwOsPU9broExyhYsBxX4spCTDX3yLgPMW go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= +go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= @@ -446,10 +470,16 @@ golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 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/crypto v0.34.0 h1:+/C6tk6rf/+t5DhUketUbD1aNGqiSX3j15Z6xuIDlBA= +golang.org/x/crypto v0.34.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= 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/exp v0.0.0-20250215185904-eff6e970281f h1:oFMYAjX0867ZD2jcNiLBrI9BdpmEkvPyi5YrBGXbamg= golang.org/x/exp v0.0.0-20250215185904-eff6e970281f/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= 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= @@ -483,6 +513,8 @@ 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/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -557,8 +589,16 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/api v0.0.0-20250219182151-9fdb1cabc7b2 h1:35ZFtrCgaAjF7AFAK0+lRSf+4AyYnWRbH7og13p7rZ4= +google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:W9ynFDP/shebLB1Hl/ESTOap2jHd6pmLXPNZC7SVDbA= +google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 h1:ilJhrCga0AptpJZXmUYG4MCrx/zf3l1okuYz7YK9PPw= +google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA= 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/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 h1:DMTIbak9GhdaSxEjvVzAeNZvyc03I61duqNbnm3SU0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 h1:ZSlhAUqC4r8TPzqLXQ0m3upBNZeF+Y8jQ3c4CR3Ujms= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= 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= @@ -639,6 +679,8 @@ modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw= modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic= +modernc.org/sqlite v1.36.0 h1:EQXNRn4nIS+gfsKeUTymHIz1waxuv5BzU7558dHSfH8= +modernc.org/sqlite v1.36.0/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU= 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=