⬆️ upgrade dependencies
@@ -86,7 +86,7 @@ func (l *FaceRecognitionLogic) FaceRecognition(in *pb.FaceRecognitionRequest) (*
|
||||
l.svcCtx.FaceRecognizer.SetSamples(samples, ids)
|
||||
|
||||
// 人脸分类
|
||||
classify := l.svcCtx.FaceRecognizer.ClassifyThreshold(faceFeatures.Descriptor, 0.3)
|
||||
classify := l.svcCtx.FaceRecognizer.ClassifyThreshold(faceFeatures.Descriptor, 0.2)
|
||||
if classify > 0 {
|
||||
return &pb.FaceRecognitionResponse{
|
||||
FaceId: int64(classify),
|
||||
@@ -242,10 +242,10 @@ func (l *FaceRecognitionLogic) saveCroppedFaceToLocal(faceImage []byte, rect ima
|
||||
// 增加边距(比如 20 像素)
|
||||
margin := 20
|
||||
extendedRect := image.Rect(
|
||||
max(rect.Min.X-margin, imgBounds.Min.X), // 确保不超出左边界
|
||||
max(rect.Min.Y-margin, imgBounds.Min.Y), // 确保不超出上边界
|
||||
min(rect.Max.X+margin, imgBounds.Max.X), // 确保不超出右边界
|
||||
min(rect.Max.Y+margin, imgBounds.Max.Y), // 确保不超出下边界
|
||||
max(rect.Min.X-margin, imgBounds.Min.X),
|
||||
max(rect.Min.Y-margin, imgBounds.Min.Y),
|
||||
min(rect.Max.X+margin, imgBounds.Max.X),
|
||||
min(rect.Max.Y+margin, imgBounds.Max.Y),
|
||||
)
|
||||
// 裁剪图像
|
||||
croppedImage := img.(interface {
|
||||
|
@@ -1,7 +1,9 @@
|
||||
package aiservicelogic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"image"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/aisvc/rpc/internal/svc"
|
||||
"schisandra-album-cloud-microservices/app/aisvc/rpc/pb"
|
||||
@@ -25,12 +27,15 @@ func NewImageClarityLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Imag
|
||||
|
||||
// ImageClarity 图像清晰度检测
|
||||
func (l *ImageClarityLogic) ImageClarity(in *pb.ImageClarityRequest) (*pb.ImageClarityResponse, error) {
|
||||
blurred, confidence, err := l.svcCtx.Clarity.Detect(in.Image)
|
||||
img, _, err := image.Decode(bytes.NewReader(in.Image))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
check, err := l.svcCtx.ClarityDetector.ClarityCheck(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.ImageClarityResponse{
|
||||
IsBlurred: blurred,
|
||||
Confidence: float32(confidence),
|
||||
IsBlurred: check,
|
||||
}, nil
|
||||
}
|
||||
|
@@ -17,16 +17,16 @@ import (
|
||||
)
|
||||
|
||||
type ServiceContext struct {
|
||||
Config config.Config
|
||||
FaceRecognizer *face.Recognizer
|
||||
DB *query.Query
|
||||
RedisClient *redis.Client
|
||||
TfNet *gocv.Net
|
||||
TfDesc []string
|
||||
CaffeNet *gocv.Net
|
||||
CaffeDesc []string
|
||||
MinioClient *minio.Client
|
||||
Clarity *clarity.Detector
|
||||
Config config.Config
|
||||
FaceRecognizer *face.Recognizer
|
||||
DB *query.Query
|
||||
RedisClient *redis.Client
|
||||
TfNet *gocv.Net
|
||||
TfDesc []string
|
||||
CaffeNet *gocv.Net
|
||||
CaffeDesc []string
|
||||
MinioClient *minio.Client
|
||||
ClarityDetector *clarity.ConcurrentDetector
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
@@ -44,6 +44,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
CaffeNet: caffeClassifier,
|
||||
CaffeDesc: caffeDesc,
|
||||
MinioClient: miniox.NewMinio(c.Minio.Endpoint, c.Minio.AccessKeyID, c.Minio.SecretAccessKey, c.Minio.UseSSL),
|
||||
Clarity: clarity.NewDetector(clarity.WithConcurrency(8), clarity.WithBaseThreshold(90), clarity.WithEdgeBoost(1.2), clarity.WithSampleScale(1)),
|
||||
ClarityDetector: clarity.NewConcurrentDetector(clarity.WithMeanThreshold(13.0), // 提高均值阈值
|
||||
clarity.WithLaplaceStdThreshold(25.0), // 提高标准差阈值
|
||||
clarity.WithMaxWorkers(8)),
|
||||
}
|
||||
}
|
||||
|
@@ -365,7 +365,7 @@ type (
|
||||
timeout: 10s // 超时时间
|
||||
maxBytes: 10485760 // 最大请求大小
|
||||
signature: false // 是否开启签名验证
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware // 注册中间件
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware,AuthMiddleware // 注册中间件
|
||||
MaxConns: true // 是否开启最大连接数限制
|
||||
Recover: true // 是否开启自动恢复
|
||||
jwt: Auth // 是否开启jwt验证
|
||||
@@ -727,6 +727,20 @@ type (
|
||||
ShareRecentInfoResponse {
|
||||
Records []ShareRecentMeta `json:"records"`
|
||||
}
|
||||
PrivateImageListRequest {
|
||||
Provider string `json:"provider"`
|
||||
Bucket string `json:"bucket"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
CoordinateMeta {
|
||||
ID int64 `json:"id"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
ImageCount int64 `json:"image_count"`
|
||||
}
|
||||
CoordinateListResponse {
|
||||
Records []CoordinateMeta `json:"records"`
|
||||
}
|
||||
)
|
||||
|
||||
// 文件上传
|
||||
@@ -736,7 +750,7 @@ type (
|
||||
timeout: 20s // 超时时间
|
||||
maxBytes: 104857600 // 最大请求大小
|
||||
signature: false // 是否开启签名验证
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware // 注册中间件
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware,AuthMiddleware // 注册中间件
|
||||
MaxConns: true // 是否开启最大连接数限制
|
||||
Recover: true // 是否开启自动恢复
|
||||
jwt: Auth // 是否开启jwt验证
|
||||
@@ -865,6 +879,14 @@ service auth {
|
||||
// 获取分享最近的数据统计
|
||||
@handler getShareRecentInfo
|
||||
post /share/recent/info returns (ShareRecentInfoResponse)
|
||||
|
||||
// 获取隐私加密图片
|
||||
@handler getPrivateImageList
|
||||
post /image/private/list (PrivateImageListRequest) returns (AllImageListResponse)
|
||||
|
||||
// 获取图像经纬度列表
|
||||
@handler getCoordinateList
|
||||
post /coordinate/list returns (CoordinateListResponse)
|
||||
}
|
||||
|
||||
type (
|
||||
@@ -951,7 +973,7 @@ type (
|
||||
timeout: 10s // 超时时间
|
||||
maxBytes: 104857600 // 最大请求大小
|
||||
signature: false // 是否开启签名验证
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware // 注册中间件
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware,AuthMiddleware // 注册中间件
|
||||
MaxConns: true // 是否开启最大连接数限制
|
||||
Recover: true // 是否开启自动恢复
|
||||
jwt: Auth // 是否开启jwt验证
|
||||
@@ -993,14 +1015,14 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// 分享服务
|
||||
// 用户服务
|
||||
@server (
|
||||
group: auth // 微服务分组
|
||||
prefix: /api/auth/user // 微服务前缀
|
||||
timeout: 10s // 超时时间
|
||||
maxBytes: 104857600 // 最大请求大小
|
||||
signature: false // 是否开启签名验证
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware // 注册中间件
|
||||
middleware: SecurityHeadersMiddleware,CasbinVerifyMiddleware,NonceMiddleware,AuthMiddleware // 注册中间件
|
||||
MaxConns: true // 是否开启最大连接数限制
|
||||
Recover: true // 是否开启自动恢复
|
||||
jwt: Auth // 是否开启jwt验证
|
||||
@@ -1009,5 +1031,9 @@ service auth {
|
||||
// 判断用户安全设置
|
||||
@handler checkUserSecuritySetting
|
||||
post /check/security/setting returns (UserSecuritySettingResponse)
|
||||
|
||||
// 退出登录
|
||||
@handler logout
|
||||
post /logout returns (string)
|
||||
}
|
||||
|
||||
|
@@ -90,8 +90,6 @@ Signature:
|
||||
Encrypt:
|
||||
# 密钥(32)
|
||||
Key: p3380puliiep184buh8d5dvujeerqtem
|
||||
# 向量 (16)
|
||||
IV: spb7er04k2vz3dtk
|
||||
# Redis 配置
|
||||
Redis:
|
||||
# Redis 地址
|
||||
|
@@ -16,7 +16,6 @@ type Config struct {
|
||||
}
|
||||
Encrypt struct {
|
||||
Key string
|
||||
IV string
|
||||
}
|
||||
Mysql struct {
|
||||
DataSource string
|
||||
|
21
app/auth/api/internal/handler/auth/logout_handler.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/auth"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/common/xhttp"
|
||||
)
|
||||
|
||||
func LogoutHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := auth.NewLogoutLogic(r.Context(), svcCtx)
|
||||
resp, err := l.Logout()
|
||||
if err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
|
||||
} else {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
@@ -27,13 +27,18 @@ import (
|
||||
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware},
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware, serverCtx.AuthMiddleware},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/check/security/setting",
|
||||
Handler: auth.CheckUserSecuritySettingHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/logout",
|
||||
Handler: auth.LogoutHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
@@ -81,7 +86,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware},
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware, serverCtx.AuthMiddleware},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
@@ -205,7 +210,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware},
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware, serverCtx.AuthMiddleware},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
@@ -273,7 +278,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware},
|
||||
[]rest.Middleware{serverCtx.SecurityHeadersMiddleware, serverCtx.CasbinVerifyMiddleware, serverCtx.NonceMiddleware, serverCtx.AuthMiddleware},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
@@ -335,6 +340,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/config/delete",
|
||||
Handler: storage.DeleteStorageConfigHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/coordinate/list",
|
||||
Handler: storage.GetCoordinateListHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/delete/record",
|
||||
@@ -380,6 +390,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/image/location/list",
|
||||
Handler: storage.QueryLocationImageListHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/image/private/list",
|
||||
Handler: storage.GetPrivateImageListHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/image/recent/list",
|
||||
|
@@ -0,0 +1,21 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/logic/storage"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
"schisandra-album-cloud-microservices/common/xhttp"
|
||||
)
|
||||
|
||||
func GetCoordinateListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := storage.NewGetCoordinateListLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetCoordinateList()
|
||||
if err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
|
||||
} else {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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 GetPrivateImageListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PrivateImageListRequest
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
|
||||
l := storage.NewGetPrivateImageListLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetPrivateImageList(&req)
|
||||
if err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
|
||||
} else {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
38
app/auth/api/internal/logic/auth/logout_logic.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"schisandra-album-cloud-microservices/common/constant"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"schisandra-album-cloud-microservices/app/auth/api/internal/svc"
|
||||
)
|
||||
|
||||
type LogoutLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogic {
|
||||
return &LogoutLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogoutLogic) Logout() (resp string, err error) {
|
||||
uid, ok := l.ctx.Value("user_id").(string)
|
||||
if !ok {
|
||||
return "", errors.New("user_id not found")
|
||||
}
|
||||
cacheKey := constant.UserTokenPrefix + uid
|
||||
err = l.svcCtx.RedisClient.Del(l.ctx, cacheKey).Err()
|
||||
if err != nil {
|
||||
l.Logger.Error("logout failed")
|
||||
return "", errors.New("logout failed")
|
||||
}
|
||||
return "logout success", nil
|
||||
}
|
@@ -67,6 +67,7 @@ func (l *GetAlbumDetailLogic) GetAlbumDetail(req *types.AlbumDetailListRequest)
|
||||
var queryCondition []gen.Condition
|
||||
queryCondition = append(queryCondition, storageInfo.UserID.Eq(uid))
|
||||
queryCondition = append(queryCondition, storageInfo.AlbumID.Eq(req.ID))
|
||||
queryCondition = append(queryCondition, storageInfo.IsEncrypted.Eq(constant.NoEncrypt))
|
||||
// 类型筛选 1 是分享类型
|
||||
if req.Type != constant.AlbumTypeShared {
|
||||
queryCondition = append(queryCondition, storageInfo.Provider.Eq(req.Provider))
|
||||
|
@@ -0,0 +1,51 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"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 GetCoordinateListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetCoordinateListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCoordinateListLogic {
|
||||
return &GetCoordinateListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetCoordinateListLogic) GetCoordinateList() (resp *types.CoordinateListResponse, err error) {
|
||||
uid, ok := l.ctx.Value("user_id").(string)
|
||||
if !ok {
|
||||
return nil, errors.New("user_id not found")
|
||||
}
|
||||
storageLocation := l.svcCtx.DB.ScaStorageLocation
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
var records []types.CoordinateMeta
|
||||
err = storageLocation.Select(
|
||||
storageLocation.ID,
|
||||
storageLocation.Longitude,
|
||||
storageLocation.Latitude,
|
||||
storageInfo.ID.Count().As("image_count"),
|
||||
).Join(
|
||||
storageInfo,
|
||||
storageLocation.ID.EqCol(storageInfo.LocationID),
|
||||
).Where(storageLocation.UserID.Eq(uid),
|
||||
storageInfo.UserID.Eq(uid),
|
||||
).Scan(&records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &types.CoordinateListResponse{
|
||||
Records: records,
|
||||
}, nil
|
||||
}
|
@@ -74,7 +74,8 @@ func (l *GetFaceDetailListLogic) GetFaceDetailList(req *types.FaceDetailListRequ
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.FaceID.Eq(req.FaceID)).
|
||||
storageInfo.FaceID.Eq(req.FaceID),
|
||||
storageInfo.IsEncrypted.Eq(constant.NoEncrypt)).
|
||||
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -0,0 +1,289 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"gorm.io/gen"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"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"
|
||||
"sort"
|
||||
"sync"
|
||||
"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 GetPrivateImageListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
RestyClient *resty.Client
|
||||
}
|
||||
|
||||
func NewGetPrivateImageListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPrivateImageListLogic {
|
||||
return &GetPrivateImageListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
RestyClient: resty.New().
|
||||
SetTimeout(30 * time.Second). // 总超时时间
|
||||
SetRetryCount(3). // 重试次数
|
||||
SetRetryWaitTime(5 * time.Second). // 重试等待时间
|
||||
SetRetryMaxWaitTime(30 * time.Second). // 最大重试等待
|
||||
AddRetryCondition(func(r *resty.Response, err error) bool {
|
||||
return r.StatusCode() == http.StatusTooManyRequests ||
|
||||
err != nil ||
|
||||
r.StatusCode() >= 500
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetPrivateImageListLogic) GetPrivateImageList(req *types.PrivateImageListRequest) (resp *types.AllImageListResponse, err error) {
|
||||
uid, ok := l.ctx.Value("user_id").(string)
|
||||
if !ok {
|
||||
return nil, errors.New("user_id not found")
|
||||
}
|
||||
|
||||
storageInfo := l.svcCtx.DB.ScaStorageInfo
|
||||
conditions := []gen.Condition{
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Neq(constant.ImageTypeShared),
|
||||
storageInfo.IsDisplayed.Eq(0),
|
||||
storageInfo.IsEncrypted.Eq(constant.Encrypt),
|
||||
}
|
||||
var storageInfoList []types.FileInfoResult
|
||||
err = storageInfo.Select(
|
||||
storageInfo.ID,
|
||||
storageInfo.FileName,
|
||||
storageInfo.CreatedAt,
|
||||
storageInfo.Path).
|
||||
Where(conditions...).
|
||||
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(storageInfoList) == 0 {
|
||||
return &types.AllImageListResponse{}, 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")
|
||||
}
|
||||
|
||||
// 按日期进行分组
|
||||
g, ctx := errgroup.WithContext(l.ctx)
|
||||
sem := semaphore.NewWeighted(10) // 限制并发数为 10
|
||||
groupedImages := sync.Map{}
|
||||
|
||||
for _, dbFileInfo := range storageInfoList {
|
||||
dbFileInfo := dbFileInfo // 创建局部变量以避免闭包问题
|
||||
if err := sem.Acquire(ctx, 1); err != nil {
|
||||
logx.Error("Failed to acquire semaphore:", err)
|
||||
continue
|
||||
}
|
||||
g.Go(func() error {
|
||||
defer sem.Release(1)
|
||||
|
||||
// 生成单条缓存键(包含文件唯一标识)
|
||||
imageCacheKey := fmt.Sprintf("%s%s:%s:%s:%s:%v",
|
||||
constant.ImageCachePrefix,
|
||||
uid,
|
||||
"list",
|
||||
req.Provider,
|
||||
req.Bucket,
|
||||
dbFileInfo.ID)
|
||||
// 尝试获取单条缓存
|
||||
if cached, err := l.svcCtx.RedisClient.Get(l.ctx, imageCacheKey).Result(); err == nil {
|
||||
var meta types.ImageMeta
|
||||
if err := json.Unmarshal([]byte(cached), &meta); err == nil {
|
||||
parse, err := time.Parse("2006-01-02 15:04:05", meta.CreatedAt)
|
||||
if err == nil {
|
||||
logx.Error("Parse Time Error:", err)
|
||||
return nil
|
||||
}
|
||||
date := parse.Format("2006年1月2日 星期") + WeekdayMap[parse.Weekday()]
|
||||
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
|
||||
images := value.([]types.ImageMeta)
|
||||
images = append(images, meta)
|
||||
groupedImages.Store(date, images)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
weekday := WeekdayMap[dbFileInfo.CreatedAt.Weekday()]
|
||||
date := dbFileInfo.CreatedAt.Format("2006年1月2日 星期" + weekday)
|
||||
url, err := service.PresignedURL(l.ctx, ossConfig.BucketName, dbFileInfo.Path, time.Minute*30)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return err
|
||||
}
|
||||
imageBytes, err := l.DownloadAndDecrypt(l.ctx, url, uid)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return err
|
||||
}
|
||||
imageData, err := l.svcCtx.XCipher.Decrypt(imageBytes, []byte(uid))
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return err
|
||||
}
|
||||
// 使用 Load 或 Store 确保原子操作
|
||||
value, _ := groupedImages.LoadOrStore(date, []types.ImageMeta{})
|
||||
images := value.([]types.ImageMeta)
|
||||
|
||||
images = append(images, types.ImageMeta{
|
||||
ID: dbFileInfo.ID,
|
||||
FileName: dbFileInfo.FileName,
|
||||
URL: base64.StdEncoding.EncodeToString(imageData),
|
||||
Width: dbFileInfo.ThumbW,
|
||||
Height: dbFileInfo.ThumbH,
|
||||
CreatedAt: dbFileInfo.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
|
||||
// 重新存储更新后的图像列表
|
||||
groupedImages.Store(date, images)
|
||||
|
||||
// 缓存单条数据(24小时基础缓存 + 随机防雪崩)
|
||||
if data, err := json.Marshal(images); err == nil {
|
||||
expire := 24*time.Hour + time.Duration(rand.Intn(3600))*time.Second
|
||||
if err := l.svcCtx.RedisClient.Set(l.ctx, imageCacheKey, data, expire).Err(); err != nil {
|
||||
logx.Error("Failed to cache image meta:", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
// 等待所有 goroutine 完成
|
||||
if err = g.Wait(); err != nil {
|
||||
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
|
||||
})
|
||||
sort.Slice(imageList, func(i, j int) bool {
|
||||
if len(imageList[i].List) == 0 || len(imageList[j].List) == 0 {
|
||||
return false // 空列表不参与排序
|
||||
}
|
||||
createdAtI, _ := time.Parse("2006-01-02 15:04:05", imageList[i].List[0].CreatedAt)
|
||||
createdAtJ, _ := time.Parse("2006-01-02 15:04:05", imageList[j].List[0].CreatedAt)
|
||||
return createdAtI.After(createdAtJ) // 降序排序
|
||||
})
|
||||
resp = &types.AllImageListResponse{
|
||||
Records: imageList,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 提取解密操作为函数
|
||||
func (l *GetPrivateImageListLogic) 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 *GetPrivateImageListLogic) 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
|
||||
}
|
||||
|
||||
func (l *GetPrivateImageListLogic) DownloadAndDecrypt(ctx context.Context, url string, uid string) ([]byte, error) {
|
||||
resp, err := l.RestyClient.R().
|
||||
SetContext(ctx).
|
||||
SetDoNotParseResponse(true). // 保持原始响应流
|
||||
Get(url)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("request failed: %w", err)
|
||||
}
|
||||
defer resp.RawBody().Close()
|
||||
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode(), resp.Status())
|
||||
}
|
||||
|
||||
// 使用缓冲区分块读取
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err := io.Copy(buf, resp.RawBody()); err != nil {
|
||||
return nil, fmt.Errorf("read response body failed: %w", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
@@ -79,6 +79,7 @@ func (l *QueryAllImageListLogic) QueryAllImageList(req *types.AllImageListReques
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Neq(constant.ImageTypeShared),
|
||||
storageInfo.IsDisplayed.Eq(0),
|
||||
storageInfo.IsEncrypted.Eq(constant.NoEncrypt),
|
||||
}
|
||||
queryCondition = append(queryCondition, conditions...)
|
||||
if req.Type != "all" {
|
||||
|
@@ -79,7 +79,8 @@ func (l *QueryLocationDetailListLogic) QueryLocationDetailList(req *types.Locati
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageLocation.ID.Eq(req.ID)).
|
||||
storageLocation.ID.Eq(req.ID),
|
||||
storageInfo.IsEncrypted.Eq(constant.NoEncrypt)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
err = storageInfoQuery.Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
|
@@ -82,7 +82,8 @@ func (l *QueryRecentImageListLogic) QueryRecentImageList(req *types.RecentListRe
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageInfo.Type.Neq(constant.ImageTypeShared),
|
||||
storageInfo.CreatedAt.Gt(thirtyDaysAgo)).
|
||||
storageInfo.CreatedAt.Gt(thirtyDaysAgo),
|
||||
storageInfo.IsEncrypted.Eq(constant.NoEncrypt)).
|
||||
Order(storageInfo.CreatedAt.Desc()).Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -79,7 +79,8 @@ func (l *QueryThingDetailListLogic) QueryThingDetailList(req *types.ThingDetailL
|
||||
storageInfo.UserID.Eq(uid),
|
||||
storageInfo.Provider.Eq(req.Provider),
|
||||
storageInfo.Bucket.Eq(req.Bucket),
|
||||
storageExtra.Tag.Eq(req.TagName)).
|
||||
storageExtra.Tag.Eq(req.TagName),
|
||||
storageInfo.IsEncrypted.Eq(constant.NoEncrypt)).
|
||||
Order(storageInfo.CreatedAt.Desc())
|
||||
err = storageInfoQuery.Scan(&storageInfoList)
|
||||
if err != nil {
|
||||
|
@@ -110,6 +110,15 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
var imageBytes []byte
|
||||
if settingResult.Encrypt {
|
||||
encryptedData, err := l.svcCtx.XCipher.Encrypt(data, []byte(uid))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imageBytes = encryptedData
|
||||
}
|
||||
|
||||
// 上传文件到 OSS
|
||||
g.Go(func() error {
|
||||
if err := sem.Acquire(ctx, 1); err != nil {
|
||||
@@ -117,16 +126,7 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
|
||||
}
|
||||
defer sem.Release(1)
|
||||
|
||||
// 重新创建 `multipart.File` 兼容的 `Reader`
|
||||
fileReader := struct {
|
||||
*bytes.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: bytes.NewReader(data),
|
||||
Closer: io.NopCloser(nil),
|
||||
}
|
||||
|
||||
fileUrl, thumbUrl, err := l.uploadFileToOSS(uid, header, fileReader, thumbnail, result)
|
||||
fileUrl, thumbUrl, err := l.uploadFileToOSS(uid, header, bytes.NewReader(imageBytes), thumbnail, result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -148,6 +148,7 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
|
||||
FileSize: header.Size,
|
||||
FilePath: filePath,
|
||||
ThumbPath: thumbPath,
|
||||
Setting: settingResult,
|
||||
}
|
||||
// 转换为 JSON
|
||||
messageData, err := json.Marshal(fileUploadMessage)
|
||||
@@ -209,7 +210,7 @@ func (l *UploadFileLogic) parseUploadSettingResult(r *http.Request) (types.Uploa
|
||||
}
|
||||
|
||||
// 上传文件到 OSS
|
||||
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File, thumbnail multipart.File, result types.File) (string, string, error) {
|
||||
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file io.Reader, thumbnail io.Reader, result types.File) (string, string, error) {
|
||||
cacheKey := constant.UserOssConfigPrefix + uid + ":" + result.Provider
|
||||
ossConfig, err := l.getOssConfigFromCacheOrDb(cacheKey, uid, result.Provider)
|
||||
if err != nil {
|
||||
|
43
app/auth/api/internal/middleware/auth_middleware.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"net/http"
|
||||
"schisandra-album-cloud-microservices/common/constant"
|
||||
"schisandra-album-cloud-microservices/common/errors"
|
||||
"schisandra-album-cloud-microservices/common/xhttp"
|
||||
)
|
||||
|
||||
type AuthMiddleware struct {
|
||||
RedisClient *redis.Client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func NewAuthMiddleware(redisClient *redis.Client) *AuthMiddleware {
|
||||
return &AuthMiddleware{
|
||||
RedisClient: redisClient,
|
||||
ctx: context.Background(),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
userId := r.Header.Get(constant.UID_HEADER_KEY)
|
||||
if userId == "" {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusNotFound, "user id not found in header"))
|
||||
return
|
||||
}
|
||||
cacheToken := constant.UserTokenPrefix + userId
|
||||
result, err := m.RedisClient.Get(m.ctx, cacheToken).Result()
|
||||
if err != nil {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusInternalServerError, err.Error()))
|
||||
return
|
||||
}
|
||||
if result == "" {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusForbidden, "access denied"))
|
||||
return
|
||||
}
|
||||
next(w, r)
|
||||
}
|
||||
}
|
@@ -21,9 +21,13 @@ func NewCasbinVerifyMiddleware(casbin *casbin.SyncedCachedEnforcer) *CasbinVerif
|
||||
func (m *CasbinVerifyMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
userId := r.Header.Get(constant.UID_HEADER_KEY)
|
||||
if userId == "" {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusNotFound, "user id not found in header"))
|
||||
return
|
||||
}
|
||||
correct, err := m.casbin.Enforce(userId, r.URL.Path, r.Method)
|
||||
if err != nil || !correct {
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusNotFound, "not found"))
|
||||
xhttp.JsonBaseResponseCtx(r.Context(), w, errors.New(http.StatusNotFound, "casbin verify failed"))
|
||||
return
|
||||
}
|
||||
next(w, r)
|
||||
|
@@ -61,7 +61,7 @@ func (c *NsqImageProcessConsumer) HandleMessage(msg *nsq.Message) error {
|
||||
}
|
||||
|
||||
// 将文件信息存入数据库
|
||||
storageId, err := c.saveFileInfoToDB(message.UID, message.Result.Bucket, message.Result.Provider, message.FileName, message.FileSize, message.Result, message.FaceID, message.FilePath, locationId, message.Result.AlbumId)
|
||||
storageId, err := c.saveFileInfoToDB(message.UID, message.Result.Bucket, message.Result.Provider, message.FileName, message.FileSize, message.Result, message.FaceID, message.FilePath, locationId, message.Result.AlbumId, message.Setting.Encrypt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -266,7 +266,7 @@ func (c *NsqImageProcessConsumer) saveFileThumbnailInfoToDB(uid string, filePath
|
||||
}
|
||||
|
||||
// 将 EXIF 和文件信息存入数据库
|
||||
func (c *NsqImageProcessConsumer) saveFileInfoToDB(uid, bucket, provider string, fileName string, fileSize int64, result types.File, faceId int64, filePath string, locationID, albumId int64) (int64, error) {
|
||||
func (c *NsqImageProcessConsumer) saveFileInfoToDB(uid, bucket, provider string, fileName string, fileSize int64, result types.File, faceId int64, filePath string, locationID, albumId int64, encrypt bool) (int64, error) {
|
||||
tx := c.svcCtx.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -274,21 +274,26 @@ func (c *NsqImageProcessConsumer) saveFileInfoToDB(uid, bucket, provider string,
|
||||
logx.Errorf("transaction rollback: %v", r)
|
||||
}
|
||||
}()
|
||||
var isEncrypted int64 = 0
|
||||
if encrypt {
|
||||
isEncrypted = 1
|
||||
}
|
||||
typeName := c.classifyFile(result.FileType, result.IsScreenshot)
|
||||
scaStorageInfo := &model.ScaStorageInfo{
|
||||
UserID: uid,
|
||||
Provider: provider,
|
||||
Bucket: bucket,
|
||||
FileName: fileName,
|
||||
FileSize: fileSize,
|
||||
FileType: result.FileType,
|
||||
Path: filePath,
|
||||
FaceID: faceId,
|
||||
Type: typeName,
|
||||
Width: result.Width,
|
||||
Height: result.Height,
|
||||
LocationID: locationID,
|
||||
AlbumID: albumId,
|
||||
UserID: uid,
|
||||
Provider: provider,
|
||||
Bucket: bucket,
|
||||
FileName: fileName,
|
||||
FileSize: fileSize,
|
||||
FileType: result.FileType,
|
||||
Path: filePath,
|
||||
FaceID: faceId,
|
||||
Type: typeName,
|
||||
Width: result.Width,
|
||||
Height: result.Height,
|
||||
LocationID: locationID,
|
||||
AlbumID: albumId,
|
||||
IsEncrypted: isEncrypted,
|
||||
}
|
||||
err := tx.ScaStorageInfo.Create(scaStorageInfo)
|
||||
if err != nil {
|
||||
|
@@ -3,6 +3,7 @@ package svc
|
||||
import (
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/landaiqing/go-xcipher"
|
||||
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/nsqio/go-nsq"
|
||||
@@ -37,6 +38,7 @@ type ServiceContext struct {
|
||||
SecurityHeadersMiddleware rest.Middleware
|
||||
CasbinVerifyMiddleware rest.Middleware
|
||||
NonceMiddleware rest.Middleware
|
||||
AuthMiddleware rest.Middleware
|
||||
DB *query.Query
|
||||
RedisClient *redis.Client
|
||||
Ip2Region *xdb.Searcher
|
||||
@@ -50,6 +52,7 @@ type ServiceContext struct {
|
||||
GeoRegionData *geo_json.RegionData
|
||||
NSQProducer *nsq.Producer
|
||||
ZincClient *zincx.ZincClient
|
||||
XCipher *xcipher.XCipher
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
@@ -61,6 +64,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
SecurityHeadersMiddleware: middleware.NewSecurityHeadersMiddleware().Handle,
|
||||
CasbinVerifyMiddleware: middleware.NewCasbinVerifyMiddleware(casbinEnforcer).Handle,
|
||||
NonceMiddleware: middleware.NewNonceMiddleware(redisClient).Handle,
|
||||
AuthMiddleware: middleware.NewAuthMiddleware(redisClient).Handle,
|
||||
DB: queryDB,
|
||||
RedisClient: redisClient,
|
||||
Ip2Region: ip2region.NewIP2Region(),
|
||||
@@ -75,6 +79,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
GeoRegionData: geo_json.NewGeoJSON(),
|
||||
NSQProducer: nsqx.NewNsqProducer(c.NSQ.NSQDHost),
|
||||
ZincClient: zincx.NewZincClient(c.Zinc.URL, c.Zinc.Username, c.Zinc.Password),
|
||||
XCipher: xcipher.NewXCipher([]byte(c.Encrypt.Key)),
|
||||
}
|
||||
return serviceContext
|
||||
}
|
||||
|
@@ -34,16 +34,18 @@ type UploadSetting struct {
|
||||
TargetDetection bool `json:"target_detection"`
|
||||
QrcodeDetection bool `json:"qrcode_detection"`
|
||||
FaceDetection bool `json:"face_detection"`
|
||||
Encrypt bool `json:"encrypt"`
|
||||
}
|
||||
|
||||
type FileUploadMessage struct {
|
||||
FaceID int64 `json:"face_id"`
|
||||
FileName string `json:"file_name"`
|
||||
FileSize int64 `json:"file_size"`
|
||||
Result File `json:"result"`
|
||||
UID string `json:"uid"`
|
||||
FilePath string `json:"file_path"`
|
||||
ThumbPath string `json:"thumb_path"`
|
||||
FaceID int64 `json:"face_id"`
|
||||
FileName string `json:"file_name"`
|
||||
FileSize int64 `json:"file_size"`
|
||||
Result File `json:"result"`
|
||||
UID string `json:"uid"`
|
||||
FilePath string `json:"file_path"`
|
||||
ThumbPath string `json:"thumb_path"`
|
||||
Setting UploadSetting `json:"setting"`
|
||||
}
|
||||
|
||||
type FileInfoResult struct {
|
||||
|
@@ -166,6 +166,17 @@ type CommentResponse struct {
|
||||
ReplyTo int64 `json:"reply_to,optional"`
|
||||
}
|
||||
|
||||
type CoordinateListResponse struct {
|
||||
Records []CoordinateMeta `json:"records"`
|
||||
}
|
||||
|
||||
type CoordinateMeta struct {
|
||||
ID int64 `json:"id"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
ImageCount int64 `json:"image_count"`
|
||||
}
|
||||
|
||||
type DeleteImageRequest struct {
|
||||
IDS []int64 `json:"ids"`
|
||||
Provider string `json:"provider"`
|
||||
@@ -310,6 +321,12 @@ type PhoneLoginRequest struct {
|
||||
AutoLogin bool `json:"auto_login"`
|
||||
}
|
||||
|
||||
type PrivateImageListRequest struct {
|
||||
Provider string `json:"provider"`
|
||||
Bucket string `json:"bucket"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type QueryDeleteRecordRequest struct {
|
||||
Provider string `json:"provider"`
|
||||
Bucket string `json:"bucket"`
|
||||
|
@@ -29,6 +29,7 @@ type ScaStorageInfo struct {
|
||||
IsDisplayed int64 `gorm:"column:is_displayed;type:tinyint(4);comment:是否隐藏(0 不隐藏 1 隐藏)" json:"is_displayed"` // 是否隐藏(0 不隐藏 1 隐藏)
|
||||
AlbumID int64 `gorm:"column:album_id;type:bigint(20);comment:相册ID" json:"album_id"` // 相册ID
|
||||
LocationID int64 `gorm:"column:location_id;type:bigint(20);comment:地址ID" json:"location_id"` // 地址ID
|
||||
IsEncrypted int64 `gorm:"column:is_encrypted;type:tinyint(4);comment:是否加密(0 否 1 是)" json:"is_encrypted"` // 是否加密(0 否 1 是)
|
||||
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"` // 删除时间
|
||||
|
@@ -42,6 +42,7 @@ func newScaStorageInfo(db *gorm.DB, opts ...gen.DOOption) scaStorageInfo {
|
||||
_scaStorageInfo.IsDisplayed = field.NewInt64(tableName, "is_displayed")
|
||||
_scaStorageInfo.AlbumID = field.NewInt64(tableName, "album_id")
|
||||
_scaStorageInfo.LocationID = field.NewInt64(tableName, "location_id")
|
||||
_scaStorageInfo.IsEncrypted = field.NewInt64(tableName, "is_encrypted")
|
||||
_scaStorageInfo.CreatedAt = field.NewTime(tableName, "created_at")
|
||||
_scaStorageInfo.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||
_scaStorageInfo.DeletedAt = field.NewField(tableName, "deleted_at")
|
||||
@@ -71,6 +72,7 @@ type scaStorageInfo struct {
|
||||
IsDisplayed field.Int64 // 是否隐藏(0 不隐藏 1 隐藏)
|
||||
AlbumID field.Int64 // 相册ID
|
||||
LocationID field.Int64 // 地址ID
|
||||
IsEncrypted field.Int64 // 是否加密(0 否 1 是)
|
||||
CreatedAt field.Time // 创建时间
|
||||
UpdatedAt field.Time // 更新时间
|
||||
DeletedAt field.Field // 删除时间
|
||||
@@ -105,6 +107,7 @@ func (s *scaStorageInfo) updateTableName(table string) *scaStorageInfo {
|
||||
s.IsDisplayed = field.NewInt64(table, "is_displayed")
|
||||
s.AlbumID = field.NewInt64(table, "album_id")
|
||||
s.LocationID = field.NewInt64(table, "location_id")
|
||||
s.IsEncrypted = field.NewInt64(table, "is_encrypted")
|
||||
s.CreatedAt = field.NewTime(table, "created_at")
|
||||
s.UpdatedAt = field.NewTime(table, "updated_at")
|
||||
s.DeletedAt = field.NewField(table, "deleted_at")
|
||||
@@ -124,7 +127,7 @@ func (s *scaStorageInfo) GetFieldByName(fieldName string) (field.OrderExpr, bool
|
||||
}
|
||||
|
||||
func (s *scaStorageInfo) fillFieldMap() {
|
||||
s.fieldMap = make(map[string]field.Expr, 18)
|
||||
s.fieldMap = make(map[string]field.Expr, 19)
|
||||
s.fieldMap["id"] = s.ID
|
||||
s.fieldMap["user_id"] = s.UserID
|
||||
s.fieldMap["provider"] = s.Provider
|
||||
@@ -140,6 +143,7 @@ func (s *scaStorageInfo) fillFieldMap() {
|
||||
s.fieldMap["is_displayed"] = s.IsDisplayed
|
||||
s.fieldMap["album_id"] = s.AlbumID
|
||||
s.fieldMap["location_id"] = s.LocationID
|
||||
s.fieldMap["is_encrypted"] = s.IsEncrypted
|
||||
s.fieldMap["created_at"] = s.CreatedAt
|
||||
s.fieldMap["updated_at"] = s.UpdatedAt
|
||||
s.fieldMap["deleted_at"] = s.DeletedAt
|
||||
|
BIN
common/clarity/1.jpg
Normal file
After Width: | Height: | Size: 3.4 MiB |
BIN
common/clarity/2.jpg
Normal file
After Width: | Height: | Size: 3.7 MiB |
Before Width: | Height: | Size: 246 KiB |
Before Width: | Height: | Size: 15 KiB |
BIN
common/clarity/3.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
common/clarity/4.jpg
Normal file
After Width: | Height: | Size: 953 KiB |
Before Width: | Height: | Size: 276 KiB |
BIN
common/clarity/5.jpg
Normal file
After Width: | Height: | Size: 3.7 MiB |
@@ -1,260 +1,183 @@
|
||||
package clarity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"math"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"gocv.io/x/gocv"
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
// Detector 图片模糊检测器
|
||||
type Detector struct {
|
||||
baseThreshold float64 // 基准阈值
|
||||
sampleScale int // 采样比例基数
|
||||
edgeBoost float64 // 边缘增强系数
|
||||
noiseFloor float64 // 噪声基底
|
||||
channelWeights [3]float64 // RGB通道权重
|
||||
adaptiveSampling bool // 启用自适应采样
|
||||
regionWeights []float64 // 区域权重矩阵
|
||||
concurrencyLimit int64 // 最大并发数
|
||||
weightedSemaphore *semaphore.Weighted
|
||||
pool sync.Pool // 内存池
|
||||
// 模糊检测器
|
||||
type ConcurrentDetector struct {
|
||||
maxWorkers int64 // 最大并发数
|
||||
meanThreshold float64 // 均值阈值
|
||||
laplaceStdThreshold float64 // Laplace标准差阈值
|
||||
sem *semaphore.Weighted
|
||||
}
|
||||
|
||||
type Option func(*Detector)
|
||||
type Option func(*ConcurrentDetector)
|
||||
|
||||
// NewDetector 创建检测器实例
|
||||
func NewDetector(opts ...Option) *Detector {
|
||||
d := &Detector{
|
||||
baseThreshold: 85.0,
|
||||
sampleScale: 2,
|
||||
edgeBoost: 1.0,
|
||||
noiseFloor: 5.0,
|
||||
channelWeights: [3]float64{0.299, 0.587, 0.114},
|
||||
adaptiveSampling: true,
|
||||
concurrencyLimit: int64(runtime.NumCPU() * 2),
|
||||
// 默认参数
|
||||
func NewConcurrentDetector(opts ...Option) *ConcurrentDetector {
|
||||
d := &ConcurrentDetector{
|
||||
maxWorkers: int64(runtime.NumCPU() * 2),
|
||||
meanThreshold: 5.0, // 原始值5
|
||||
laplaceStdThreshold: 20.0, // 原始值20
|
||||
}
|
||||
|
||||
d.pool.New = func() interface{} {
|
||||
return &scanContext{
|
||||
sum: 0,
|
||||
sumSq: 0,
|
||||
}
|
||||
}
|
||||
|
||||
d.weightedSemaphore = semaphore.NewWeighted(d.concurrencyLimit)
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(d)
|
||||
}
|
||||
|
||||
d.sem = semaphore.NewWeighted(d.maxWorkers)
|
||||
return d
|
||||
}
|
||||
|
||||
// 配置选项 ---------------------------------------------------
|
||||
|
||||
func WithBaseThreshold(t float64) Option {
|
||||
return func(d *Detector) {
|
||||
d.baseThreshold = t
|
||||
// 配置选项 -------------------------------------------------
|
||||
func WithMeanThreshold(t float64) Option {
|
||||
return func(d *ConcurrentDetector) {
|
||||
d.meanThreshold = t
|
||||
}
|
||||
}
|
||||
|
||||
func WithSampleScale(n int) Option {
|
||||
return func(d *Detector) {
|
||||
d.sampleScale = 1 << uint(maxInt(0, n))
|
||||
func WithLaplaceStdThreshold(t float64) Option {
|
||||
return func(d *ConcurrentDetector) {
|
||||
d.laplaceStdThreshold = t
|
||||
}
|
||||
}
|
||||
|
||||
func WithEdgeBoost(factor float64) Option {
|
||||
return func(d *Detector) {
|
||||
d.edgeBoost = clamp(factor, 0.5, 2.0)
|
||||
func WithMaxWorkers(n int) Option {
|
||||
return func(d *ConcurrentDetector) {
|
||||
d.maxWorkers = int64(n)
|
||||
}
|
||||
}
|
||||
|
||||
func WithNoiseFloor(floor float64) Option {
|
||||
return func(d *Detector) {
|
||||
d.noiseFloor = math.Max(0, floor)
|
||||
func (d *ConcurrentDetector) ClarityCheck(img image.Image) (bool, error) {
|
||||
if img == nil {
|
||||
return false, fmt.Errorf("nil image input")
|
||||
}
|
||||
|
||||
mat, err := gocv.ImageToMatRGB(img)
|
||||
if err != nil || mat.Empty() {
|
||||
if mat.Empty() == false {
|
||||
mat.Close()
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
matClone := mat.Clone()
|
||||
if mat.Channels() != 1 {
|
||||
gocv.CvtColor(mat, &matClone, gocv.ColorRGBToGray)
|
||||
}
|
||||
mat.Close()
|
||||
|
||||
// Canny检测部分
|
||||
destCanny := gocv.NewMat()
|
||||
defer destCanny.Close()
|
||||
gocv.Canny(matClone, &destCanny, 200, 200)
|
||||
|
||||
destCannyC := gocv.NewMat()
|
||||
defer destCannyC.Close()
|
||||
destCannyD := gocv.NewMat()
|
||||
defer destCannyD.Close()
|
||||
gocv.MeanStdDev(destCanny, &destCannyC, &destCannyD)
|
||||
if destCannyD.GetDoubleAt(0, 0) == 0 {
|
||||
matClone.Close()
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Laplace检测部分
|
||||
destA := gocv.NewMat()
|
||||
defer destA.Close()
|
||||
gocv.Laplacian(matClone, &destA, gocv.MatTypeCV64F, 3, 1, 0, gocv.BorderDefault)
|
||||
|
||||
destC := gocv.NewMat()
|
||||
defer destC.Close()
|
||||
destD := gocv.NewMat()
|
||||
defer destD.Close()
|
||||
gocv.MeanStdDev(destA, &destC, &destD)
|
||||
|
||||
destMean := gocv.NewMat()
|
||||
defer destMean.Close()
|
||||
gocv.Laplacian(matClone, &destMean, gocv.MatTypeCV16U, 3, 1, 0, gocv.BorderDefault)
|
||||
mean := destMean.Mean()
|
||||
matClone.Close()
|
||||
|
||||
// 使用可配置阈值(mean.Val1 >5 || destD.GetDoubleAt>20)
|
||||
result := mean.Val1 > d.meanThreshold && destD.GetDoubleAt(0, 0) > d.laplaceStdThreshold
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func WithConcurrency(n int) Option {
|
||||
return func(d *Detector) {
|
||||
d.concurrencyLimit = int64(maxInt(1, n))
|
||||
d.weightedSemaphore = semaphore.NewWeighted(d.concurrencyLimit)
|
||||
}
|
||||
type Result struct {
|
||||
Blurred bool
|
||||
Err error
|
||||
}
|
||||
|
||||
// Detect 执行模糊检测
|
||||
func (d *Detector) Detect(imgData []byte) (isBlurred bool, confidence float64, err error) {
|
||||
img, _, err := image.Decode(bytes.NewReader(imgData))
|
||||
if err != nil {
|
||||
return true, 0.0, err
|
||||
}
|
||||
func (d *ConcurrentDetector) BatchDetect(ctx context.Context, images <-chan image.Image) <-chan Result {
|
||||
results := make(chan Result)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
bounds := img.Bounds()
|
||||
width, height := bounds.Dx(), bounds.Dy()
|
||||
|
||||
if width < 32 || height < 32 {
|
||||
return true, 0.0, nil
|
||||
}
|
||||
|
||||
ctx := d.pool.Get().(*scanContext)
|
||||
defer d.pool.Put(ctx)
|
||||
ctx.reset()
|
||||
|
||||
step := d.calculateStep(width, height)
|
||||
|
||||
g, groupCtx := errgroup.WithContext(context.Background())
|
||||
processingCtx, cancel := context.WithCancel(groupCtx)
|
||||
defer cancel()
|
||||
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y += step {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x += step {
|
||||
x, y := x, y // 捕获循环变量
|
||||
|
||||
if err := d.weightedSemaphore.Acquire(processingCtx, 1); err != nil {
|
||||
go func() {
|
||||
defer close(results)
|
||||
for img := range images {
|
||||
if err := d.sem.Acquire(ctx, 1); err != nil {
|
||||
break
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
g.Go(func() error {
|
||||
defer d.weightedSemaphore.Release(1)
|
||||
go func(img image.Image) {
|
||||
defer wg.Done()
|
||||
defer d.sem.Release(1)
|
||||
|
||||
blurred, err := d.ClarityCheck(img)
|
||||
select {
|
||||
case <-processingCtx.Done():
|
||||
return nil
|
||||
default:
|
||||
case results <- Result{Blurred: blurred, Err: err}:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
|
||||
if x <= 0 || y <= 0 || x >= bounds.Max.X-1 || y >= bounds.Max.Y-1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
gray := d.calculateGray(img, x, y)
|
||||
val := d.calculateLaplacian(img, x, y, gray)
|
||||
weight := d.getRegionWeight(x, y, bounds)
|
||||
|
||||
ctx.mu.Lock()
|
||||
ctx.sum += val * weight
|
||||
ctx.sumSq += (val * weight) * (val * weight)
|
||||
ctx.mu.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
}(img)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return true, 0.0, err
|
||||
}
|
||||
|
||||
n := float64(((width / step) * (height / step)) - 4)
|
||||
if n <= 0 {
|
||||
return true, 0.0, nil
|
||||
}
|
||||
|
||||
mean := ctx.sum / n
|
||||
variance := (ctx.sumSq/n - mean*mean) * 1e6
|
||||
|
||||
dynamicThreshold := d.calculateDynamicThreshold(width, height)
|
||||
confidence = math.Max(0, math.Min(1, (variance-d.noiseFloor)/(dynamicThreshold-d.noiseFloor)))
|
||||
|
||||
return variance < dynamicThreshold, confidence, nil
|
||||
return results
|
||||
}
|
||||
|
||||
// 私有方法 ---------------------------------------------------
|
||||
/*
|
||||
func main() {
|
||||
// 初始化检测器(调整阈值参数)
|
||||
detector := NewConcurrentDetector(
|
||||
WithMeanThreshold(8.0), // 提高均值阈值
|
||||
WithLaplaceStdThreshold(25.0), // 提高标准差阈值
|
||||
WithMaxWorkers(8), // 设置并发数
|
||||
)
|
||||
|
||||
func (d *Detector) calculateStep(width, height int) int {
|
||||
if !d.adaptiveSampling {
|
||||
return d.sampleScale
|
||||
}
|
||||
// 准备测试图片
|
||||
img := loadImage("test.jpg")
|
||||
|
||||
area := width * height
|
||||
switch {
|
||||
case area > 4000*3000:
|
||||
return d.sampleScale * 4
|
||||
case area > 2000*1500:
|
||||
return d.sampleScale * 2
|
||||
default:
|
||||
return d.sampleScale
|
||||
// 单张检测
|
||||
blurred, _ := detector.clarityCheck(img)
|
||||
fmt.Println("Blurred:", blurred)
|
||||
|
||||
// 批量检测
|
||||
ctx := context.Background()
|
||||
imgChan := make(chan image.Image, 10)
|
||||
go func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
imgChan <- loadImage(fmt.Sprintf("image%d.jpg", i))
|
||||
}
|
||||
close(imgChan)
|
||||
}()
|
||||
|
||||
results := detector.BatchDetect(ctx, imgChan)
|
||||
for res := range results {
|
||||
if res.Err != nil {
|
||||
fmt.Println("Error:", res.Err)
|
||||
continue
|
||||
}
|
||||
fmt.Println("Result:", res.Blurred)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Detector) calculateGray(img image.Image, x, y int) float64 {
|
||||
r, g, b, _ := img.At(x, y).RGBA()
|
||||
return d.channelWeights[0]*float64(r>>8) +
|
||||
d.channelWeights[1]*float64(g>>8) +
|
||||
d.channelWeights[2]*float64(b>>8)
|
||||
}
|
||||
|
||||
func (d *Detector) calculateLaplacian(img image.Image, x, y int, center float64) float64 {
|
||||
getGray := func(x, y int) float64 {
|
||||
r, g, b, _ := img.At(x, y).RGBA()
|
||||
return d.channelWeights[0]*float64(r>>8) +
|
||||
d.channelWeights[1]*float64(g>>8) +
|
||||
d.channelWeights[2]*float64(b>>8)
|
||||
}
|
||||
|
||||
return math.Abs(4*center-
|
||||
getGray(x-1, y)-
|
||||
getGray(x+1, y)-
|
||||
getGray(x, y-1)-
|
||||
getGray(x, y+1)) * d.edgeBoost
|
||||
}
|
||||
|
||||
func (d *Detector) calculateDynamicThreshold(width, height int) float64 {
|
||||
areaRatio := float64(width*height) / 250000.0
|
||||
return d.baseThreshold*math.Pow(areaRatio, 0.65) + d.noiseFloor
|
||||
}
|
||||
|
||||
func (d *Detector) getRegionWeight(x, y int, bounds image.Rectangle) float64 {
|
||||
if len(d.regionWeights) == 0 {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
size := int(math.Sqrt(float64(len(d.regionWeights))))
|
||||
if size == 0 {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
nx := float64(x-bounds.Min.X) / float64(bounds.Dx())
|
||||
ny := float64(y-bounds.Min.Y) / float64(bounds.Dy())
|
||||
|
||||
ix := int(nx * float64(size))
|
||||
iy := int(ny * float64(size))
|
||||
idx := iy*size + ix
|
||||
|
||||
if idx >= 0 && idx < len(d.regionWeights) {
|
||||
return d.regionWeights[idx]
|
||||
}
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// 辅助函数 ---------------------------------------------------
|
||||
|
||||
type scanContext struct {
|
||||
sum float64
|
||||
sumSq float64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (c *scanContext) reset() {
|
||||
c.sum = 0
|
||||
c.sumSq = 0
|
||||
}
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func clamp(value, min, max float64) float64 {
|
||||
return math.Max(min, math.Min(max, value))
|
||||
}
|
||||
*/
|
||||
|
@@ -1,62 +0,0 @@
|
||||
package clarity
|
||||
|
||||
import (
|
||||
"gocv.io/x/gocv"
|
||||
"image"
|
||||
)
|
||||
|
||||
// 清晰度检测
|
||||
func Clarity(img image.Image) (bool, error) {
|
||||
mat, err := gocv.ImageToMatRGB(img)
|
||||
if err != nil || mat.Empty() {
|
||||
if mat.Empty() == false {
|
||||
mat.Close()
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
matClone := mat.Clone()
|
||||
// 如果图片是多通道 就进去转换
|
||||
if mat.Channels() != 1 {
|
||||
// 将图像转换为灰度显示
|
||||
gocv.CvtColor(mat, &matClone, gocv.ColorRGBToGray)
|
||||
}
|
||||
mat.Close()
|
||||
|
||||
destCanny := gocv.NewMat()
|
||||
|
||||
destCannyC := gocv.NewMat()
|
||||
|
||||
destCannyD := gocv.NewMat()
|
||||
// 边缘检测
|
||||
gocv.Canny(matClone, &destCanny, 200, 200)
|
||||
// 求矩阵的均值与标准差
|
||||
gocv.MeanStdDev(destCanny, &destCannyC, &destCannyD)
|
||||
destCanny.Close()
|
||||
destCannyC.Close()
|
||||
if destCannyD.GetDoubleAt(0, 0) == 0 {
|
||||
destCannyD.Close()
|
||||
matClone.Close()
|
||||
return false, nil
|
||||
}
|
||||
destCannyD.Close()
|
||||
|
||||
destC := gocv.NewMat()
|
||||
destD := gocv.NewMat()
|
||||
destA := gocv.NewMat()
|
||||
// Laplace算子
|
||||
gocv.Laplacian(matClone, &destA, gocv.MatTypeCV64F, 3, 1, 0, gocv.BorderDefault)
|
||||
gocv.MeanStdDev(destA, &destC, &destD)
|
||||
destC.Close()
|
||||
destA.Close()
|
||||
destMean := gocv.NewMat()
|
||||
gocv.Laplacian(matClone, &destMean, gocv.MatTypeCV16U, 3, 1, 0, gocv.BorderDefault)
|
||||
mean := destMean.Mean()
|
||||
destMean.Close()
|
||||
matClone.Close()
|
||||
if mean.Val1 > 5 || destD.GetDoubleAt(0, 0) > 20 {
|
||||
destD.Close()
|
||||
return true, nil
|
||||
}
|
||||
destD.Close()
|
||||
return false, nil
|
||||
}
|
@@ -1,27 +1,30 @@
|
||||
package clarity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClarity(t *testing.T) {
|
||||
|
||||
//detector := NewDetector(
|
||||
// WithConcurrency(8), WithBaseThreshold(90), WithEdgeBoost(1.2), WithSampleScale(1))
|
||||
//imgData, _ := os.ReadFile("4.png")
|
||||
//blurred, confidence, err := detector.Detect(imgData)
|
||||
//if err != nil {
|
||||
// t.Error(err)
|
||||
//}
|
||||
//t.Log(blurred, confidence)
|
||||
imgData, _ := os.ReadFile("2.png")
|
||||
img, _, err := image.Decode(bytes.NewReader(imgData))
|
||||
clarity, err := Clarity(img)
|
||||
imgData, err := os.Open("2.jpg")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(clarity)
|
||||
img, _, err := image.Decode(imgData)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
detector := NewConcurrentDetector(WithMeanThreshold(13.0), // 提高均值阈值
|
||||
WithLaplaceStdThreshold(25.0), // 提高标准差阈值
|
||||
WithMaxWorkers(8), // 设置并发数
|
||||
)
|
||||
check, err := detector.ClarityCheck(img)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(check)
|
||||
}
|
||||
|
@@ -7,3 +7,8 @@ const (
|
||||
ImageTypeGif = "gif"
|
||||
ImageTypeShared = "shared"
|
||||
)
|
||||
|
||||
const (
|
||||
Encrypt int64 = 1
|
||||
NoEncrypt int64 = 0
|
||||
)
|
||||
|
@@ -1,106 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestImgEncrypt(t *testing.T) {
|
||||
// 1. 读取并强制转换为RGBA
|
||||
inputFile, err := os.Open("E:\\Go_WorkSpace\\schisandra-album-cloud-microservices\\common\\img_encrypt\\input.png")
|
||||
if err != nil {
|
||||
log.Fatal("打开文件失败:", err)
|
||||
}
|
||||
defer inputFile.Close()
|
||||
|
||||
srcImg, err := png.Decode(inputFile)
|
||||
if err != nil {
|
||||
log.Fatal("解码失败:", err)
|
||||
}
|
||||
|
||||
bounds := srcImg.Bounds()
|
||||
rgba := image.NewRGBA(bounds)
|
||||
draw.Draw(rgba, bounds, srcImg, bounds.Min, draw.Src)
|
||||
|
||||
// 2. 安全加密(处理有效像素区)
|
||||
key := []byte{0x1F, 0x3A, 0x7B, 0x9C} // 示例密钥(推荐长度4/8/16)
|
||||
secureXor(rgba, key)
|
||||
|
||||
// 3. 保存加密图像(禁用压缩)
|
||||
outputFile, err := os.Create("encrypted.png")
|
||||
if err != nil {
|
||||
log.Fatal("创建文件失败:", err)
|
||||
}
|
||||
defer outputFile.Close()
|
||||
|
||||
encoder := png.Encoder{CompressionLevel: png.NoCompression}
|
||||
if err := encoder.Encode(outputFile, rgba); err != nil {
|
||||
log.Fatal("保存失败:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImgDecrypt(t *testing.T) {
|
||||
// 1. 读取加密图像
|
||||
inputFile, err := os.Open("E:\\Go_WorkSpace\\schisandra-album-cloud-microservices\\common\\img_encrypt\\encrypted.png")
|
||||
if err != nil {
|
||||
log.Fatal("打开加密文件失败:", err)
|
||||
}
|
||||
defer inputFile.Close()
|
||||
|
||||
encImg, err := png.Decode(inputFile)
|
||||
if err != nil {
|
||||
log.Fatal("解码失败:", err)
|
||||
}
|
||||
|
||||
// 2. 转换为RGBA
|
||||
bounds := encImg.Bounds()
|
||||
rgba := image.NewRGBA(bounds)
|
||||
draw.Draw(rgba, bounds, encImg, bounds.Min, draw.Src)
|
||||
|
||||
// 3. 解密(使用相同密钥)
|
||||
key := []byte{0x1F, 0x3A, 0x7B, 0x9C} // 必须与加密一致
|
||||
secureXor(rgba, key)
|
||||
|
||||
// 4. 保存解密结果
|
||||
outputFile, err := os.Create("decrypted.png")
|
||||
if err != nil {
|
||||
log.Fatal("创建解密文件失败:", err)
|
||||
}
|
||||
defer outputFile.Close()
|
||||
|
||||
encoder := png.Encoder{CompressionLevel: png.NoCompression}
|
||||
if err := encoder.Encode(outputFile, rgba); err != nil {
|
||||
log.Fatal("保存失败:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 通用加密/解密函数
|
||||
// 安全加密函数
|
||||
func secureXor(img *image.RGBA, key []byte) {
|
||||
keyLen := len(key)
|
||||
if keyLen == 0 {
|
||||
log.Fatal("密钥不能为空")
|
||||
}
|
||||
|
||||
bounds := img.Bounds()
|
||||
data := img.Pix
|
||||
stride := img.Stride
|
||||
width := bounds.Dx() * 4 // 每行实际需要的字节数
|
||||
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
rowStart := (y - bounds.Min.Y) * stride
|
||||
// 严格限定处理范围为有效像素区
|
||||
end := rowStart + width
|
||||
if end > len(data) {
|
||||
end = len(data)
|
||||
}
|
||||
|
||||
for pos := rowStart; pos < end; pos++ {
|
||||
data[pos] ^= key[pos%keyLen]
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 246 KiB |
102
go.mod
@@ -1,24 +1,28 @@
|
||||
module schisandra-album-cloud-microservices
|
||||
|
||||
go 1.23.4
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.1
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.6
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.2
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.4.1
|
||||
github.com/Kagami/go-face v0.0.0-20210630145111-0c14797b4d0e
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.0
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.1
|
||||
github.com/asjdf/gorm-cache v1.2.3
|
||||
github.com/casbin/casbin/v2 v2.103.0
|
||||
github.com/casbin/gorm-adapter/v3 v3.32.0
|
||||
github.com/ccpwcn/kgo v1.2.9
|
||||
github.com/corona10/goimagehash v1.1.0
|
||||
github.com/duke-git/lancet/v2 v2.3.4
|
||||
github.com/duke-git/lancet/v2 v2.3.5
|
||||
github.com/go-resty/resty/v2 v2.16.5
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/landaiqing/go-xcipher v0.1.0
|
||||
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.87
|
||||
github.com/minio/minio-go/v7 v7.0.88
|
||||
github.com/mssola/useragent v1.0.0
|
||||
github.com/nicksnyder/go-i18n/v2 v2.5.1
|
||||
github.com/nsqio/go-nsq v1.1.0
|
||||
@@ -30,13 +34,13 @@ require (
|
||||
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/zeromicro/go-zero v1.8.1
|
||||
github.com/zmexing/go-sensitive-word v1.3.0
|
||||
gocv.io/x/gocv v0.40.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
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/sync v0.12.0
|
||||
golang.org/x/text v0.23.0
|
||||
google.golang.org/grpc v1.71.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gen v0.3.26
|
||||
@@ -73,11 +77,10 @@ require (
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-playground/assert/v2 v2.2.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.16.5 // 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
|
||||
@@ -87,18 +90,18 @@ 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/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // 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
|
||||
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // 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.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // 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
|
||||
github.com/imroc/req/v3 v3.50.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.2 // indirect
|
||||
@@ -124,15 +127,15 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.23.0 // indirect
|
||||
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/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg6/go-requests v0.2.3 // indirect
|
||||
github.com/prometheus/client_golang v1.21.0 // indirect
|
||||
github.com/prometheus/client_golang v1.21.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/common v0.63.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.50.0 // indirect
|
||||
@@ -141,37 +144,37 @@ require (
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.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
|
||||
go.etcd.io/etcd/client/v3 v3.5.18 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.19 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.19 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.19 // 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 v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
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-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.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-20250224174004-546df14abb99 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/image v0.25.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/oauth2 v0.28.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.31.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // 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
|
||||
@@ -180,17 +183,18 @@ 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.2 // indirect
|
||||
k8s.io/apimachinery v0.32.2 // indirect
|
||||
k8s.io/client-go v0.32.2 // indirect
|
||||
k8s.io/api v0.32.3 // indirect
|
||||
k8s.io/apimachinery v0.32.3 // indirect
|
||||
k8s.io/client-go v0.32.3 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // 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.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/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
102
go.sum
@@ -2,10 +2,14 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.1 h1:SsxBygxATQpFS92pKuVtGrgdawwsscj9Y0M0jks9rTo=
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.1/go.mod h1:xFGsskCnzAu+6rFEJbGVAlwhrwZPXAny6m7j71S/B5k=
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.2 h1:IInr1YWwkhwOykxDqux1Goym0uFhrYwBjmgLnEwCLqs=
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.3.2/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.6 h1:63LAZisWFAN+2B1fTPNTkbPjiDn8pIL+yS9lbDxUvhQ=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.3.6/go.mod h1:nIs82Blb0W8QoD6qCx01Lp1W/kM+/n18BgX10UcRIkQ=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.4.1 h1:N8duKMsES4HU+t6P518/BTKPYHd4v2ggVH48TZ1Gg7M=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.4.1/go.mod h1:ybM3u4Lhso0X+ZsgoRCF4e5W1KT2fBc6plpjPZ2fop4=
|
||||
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=
|
||||
@@ -38,6 +42,8 @@ github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQg
|
||||
github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8=
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.0 h1:gUWBCekWIFWYK7jXhRvPHIa7mRhJih2BGPjzvzodO18=
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.0/go.mod h1:FTzydeQVmR24FI0D6XWUOMKckjXehM/jgMn1xC+DA9M=
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.1 h1:sOhpJdR/+lbQniznp3cYSfwQlXbVkT0ccuiZScBrI6Y=
|
||||
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.1/go.mod h1:FTzydeQVmR24FI0D6XWUOMKckjXehM/jgMn1xC+DA9M=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/asjdf/gorm-cache v1.2.3 h1:h7GAMITzk6DdpOlAGlF0dUt25N8fK4R6zeQyO0pMqlA=
|
||||
@@ -91,6 +97,8 @@ github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ
|
||||
github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4=
|
||||
github.com/duke-git/lancet/v2 v2.3.4 h1:8XGI7P9w+/GqmEBEXYaH/XuNiM0f4/90Ioti0IvYJls=
|
||||
github.com/duke-git/lancet/v2 v2.3.4/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
|
||||
github.com/duke-git/lancet/v2 v2.3.5 h1:vb49UWkkdyu2eewilZbl0L3X3T133znSQG0FaeJIBMg=
|
||||
github.com/duke-git/lancet/v2 v2.3.5/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/elastic/elastic-transport-go/v8 v8.6.1 h1:h2jQRqH6eLGiBSN4eZbQnJLtL4bC5b4lfVFRjw2R4e4=
|
||||
@@ -116,10 +124,14 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
|
||||
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
@@ -127,6 +139,7 @@ github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
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=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
@@ -155,6 +168,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
|
||||
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/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/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=
|
||||
@@ -170,6 +185,8 @@ 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-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 h1:+J3r2e8+RsmN3vKfo75g0YSY61ms37qzPglu4p0sGro=
|
||||
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7/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=
|
||||
@@ -179,8 +196,11 @@ 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 v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
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/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
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=
|
||||
@@ -192,6 +212,8 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/imroc/req/v3 v3.49.1 h1:Nvwo02riiPEzh74ozFHeEJrtjakFxnoWNR3YZYuQm9U=
|
||||
github.com/imroc/req/v3 v3.49.1/go.mod h1:tsOk8K7zI6cU4xu/VWCZVtq9Djw9IWm4MslKzme5woU=
|
||||
github.com/imroc/req/v3 v3.50.0 h1:n3BVnZiTRpvkN5T1IB79LC/THhFU9iXksNRMH4ZNVaY=
|
||||
github.com/imroc/req/v3 v3.50.0/go.mod h1:tsOk8K7zI6cU4xu/VWCZVtq9Djw9IWm4MslKzme5woU=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
@@ -233,6 +255,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/landaiqing/go-xcipher v0.1.0 h1:VjFFWAqE2B8HCAY8IFq0tyl8k8nh42x1HoxSrB34dqk=
|
||||
github.com/landaiqing/go-xcipher v0.1.0/go.mod h1:uBtPlTbWPHWRakmQiKFnoqqU/w54StrxZ+PmE7IUWfo=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20241220152942-06eb5c6e8230 h1:B0oaMTAQKDZd8cwYT0qsAI7+c3KbFeBNA8GhgoBMXWw=
|
||||
@@ -259,6 +283,8 @@ 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.87 h1:nkr9x0u53PespfxfUqxP3UYWiE2a41gaofgNnC4Y8WQ=
|
||||
github.com/minio/minio-go/v7 v7.0.87/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg=
|
||||
github.com/minio/minio-go/v7 v7.0.88 h1:v8MoIJjwYxOkehp+eiLIuvXk87P2raUtoU5klrAAshs=
|
||||
github.com/minio/minio-go/v7 v7.0.88/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=
|
||||
@@ -287,6 +313,8 @@ 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/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
|
||||
github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
|
||||
@@ -316,10 +344,14 @@ 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.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA=
|
||||
github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/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=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
@@ -382,14 +414,22 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M
|
||||
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||
github.com/zeromicro/go-zero v1.8.0 h1:4g/8VW+fOyM51HZYPeI3mXIZdEX+Fl6SsdYX2H5PYw4=
|
||||
github.com/zeromicro/go-zero v1.8.0/go.mod h1:xDBF+/iDzj30zPvu6HNUIbpz1J6+/g3Sx9D/DytJfss=
|
||||
github.com/zeromicro/go-zero v1.8.1 h1:iUYQEMQzS9Pb8ebzJtV3FGtv/YTjZxAh/NvLW/316wo=
|
||||
github.com/zeromicro/go-zero v1.8.1/go.mod h1:gc54Ad4qt7OJ0PbKajnYsSKsZBYN4JLRIXKlqDX2A2I=
|
||||
github.com/zmexing/go-sensitive-word v1.3.0 h1:dB9S9kNklksOODGLLAov0RaVCwC2w9Kwxz6NZMdM6rk=
|
||||
github.com/zmexing/go-sensitive-word v1.3.0/go.mod h1:wkNIpkq1iPOe3l7l83zvnnV5mm20jfj2x8V8kjOTsUM=
|
||||
go.etcd.io/etcd/api/v3 v3.5.18 h1:Q4oDAKnmwqTo5lafvB+afbgCDF7E35E4EYV2g+FNGhs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.18/go.mod h1:uY03Ob2H50077J7Qq0DeehjM/A9S8PhVfbQ1mSaMopU=
|
||||
go.etcd.io/etcd/api/v3 v3.5.19 h1:w3L6sQZGsWPuBxRQ4m6pPP3bVUtV8rjW033EGwlr0jw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.19/go.mod h1:QqKGViq4KTgOG43dr/uH0vmGWIaoJY3ggFi6ZH0TH/U=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.18 h1:mZPOYw4h8rTk7TeJ5+3udUkfVGBqc+GCjOJYd68QgNM=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.18/go.mod h1:BxVf2o5wXG9ZJV+/Cu7QNUiJYk4A29sAhoI5tIRsCu4=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.19 h1:9VsyGhg0WQGjDWWlDI4VuaS9PZJGNbPkaHEIuLwtixk=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.19/go.mod h1:qaOi1k4ZA9lVLejXNvyPABrVEe7VymMF2433yyRQ7O0=
|
||||
go.etcd.io/etcd/client/v3 v3.5.18 h1:nvvYmNHGumkDjZhTHgVU36A9pykGa2K4lAJ0yY7hcXA=
|
||||
go.etcd.io/etcd/client/v3 v3.5.18/go.mod h1:kmemwOsPU9broExyhYsBxX4spCTDX3yLgPMWtpBXG6E=
|
||||
go.etcd.io/etcd/client/v3 v3.5.19 h1:+4byIz6ti3QC28W0zB0cEZWwhpVHXdrKovyycJh1KNo=
|
||||
go.etcd.io/etcd/client/v3 v3.5.19/go.mod h1:FNzyinmMIl0oVsty1zA3hFeUrxXI/JpEnz4sG+POzjU=
|
||||
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
|
||||
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
@@ -397,26 +437,45 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.34.0 h1:jBpDk4HAUsrnVO1FsfCfCOTEc/MkInJmvfCHYLFiT80=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.34.0/go.mod h1:H9LUIM1daaeZaz91vZcfeM0fejXPmgCYE8ZhzqfJuiU=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 h1:T0Ec2E+3YZf5bgTNQVet8iTDW7oIk03tXHq+wkwIDnE=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0/go.mod h1:30v2gqH+vYGJsesLWFov8u47EpYTcIQcBjKpI6pJThg=
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.34.0 h1:GSjCkoYqsnvUMCjxF18j2tCWH8fhGZYjH3iYgechPTI=
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.34.0/go.mod h1:h830hluwAqgSNnZbxL2rJhmAlE7/0SF9esoHVLU04Gc=
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.35.0 h1:OAx1AdClqTB3pz+B4osLuGjx8kubys8ByW7yx0lF454=
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.35.0/go.mod h1:hz5wHI9hmCXzwkXFGZ05ObZw2Q2t/AeAZ18PExd2uSM=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
@@ -445,11 +504,17 @@ 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.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
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/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||
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=
|
||||
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -457,6 +522,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -478,8 +545,12 @@ 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.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
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/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||
golang.org/x/oauth2 v0.28.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=
|
||||
@@ -488,6 +559,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -510,6 +583,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -522,6 +597,8 @@ golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -536,8 +613,12 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@@ -548,16 +629,24 @@ 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.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||
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-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/api v0.0.0-20250313205543-e70fdf4c4cb4 h1:IFnXJq3UPB3oBREOodn1v1aGQeZYQclEmvWRMN0PSsY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:c8q6Z6OCqnfVIqUFJkCzKcrj8eCvUrz+K4KRzSTuANg=
|
||||
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/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/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/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
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.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
@@ -606,14 +695,22 @@ gorm.io/plugin/optimisticlock v1.1.3 h1:uFK8zz+Ln6ju3vGkTd1LY3xR2VBmMxjdU12KBb58
|
||||
gorm.io/plugin/optimisticlock v1.1.3/go.mod h1:S+MH7qnHGQHxDBc9phjgN+DpNPn/qESd1q69fA3dtkg=
|
||||
k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw=
|
||||
k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y=
|
||||
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=
|
||||
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k=
|
||||
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
|
||||
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
||||
k8s.io/apimachinery v0.32.3/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/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
|
||||
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
|
||||
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=
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=
|
||||
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 h1:t0huyHnz6HsokckRxAF1bY0cqPFwzINKCL7yltEjZQc=
|
||||
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||
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=
|
||||
@@ -642,7 +739,12 @@ modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|