diff --git a/.golangci.yml b/.golangci.yml index c41ff71..0677436 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -11,8 +11,7 @@ linters: - goconst - gocritic - gocyclo - - gofmt - - goimports + # - goimports - goprintffuncname - gosimple - govet @@ -27,7 +26,6 @@ linters: - unconvert - unparam - whitespace - - gofumpt disable: - unused diff --git a/.goreleaser.yaml b/.goreleaser.yaml index dce2bb9..c493cec 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -41,7 +41,7 @@ signs: "--output", "${signature}", "--detach-sign", - "${artifact}", + "${artifact}" ] snapshot: diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..33fcf56 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,5 @@ +singleQuote: false +semi: false +printWidth: 100 +trailingComma: none +endOfLine: crlf diff --git a/cmd/web.go b/cmd/web.go index a628d4c..2224a75 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -4,13 +4,12 @@ import ( "fmt" "github.com/TensoRaws/NuxBT-Backend/internal/router" - "github.com/urfave/cli/v2" - - "github.com/TensoRaws/NuxBT-Backend/internal/middleware/cache" + "github.com/TensoRaws/NuxBT-Backend/module/cache" "github.com/TensoRaws/NuxBT-Backend/module/config" "github.com/TensoRaws/NuxBT-Backend/module/db" "github.com/TensoRaws/NuxBT-Backend/module/log" "github.com/TensoRaws/NuxBT-Backend/module/oss" + "github.com/urfave/cli/v2" ) // CmdWeb api 子命令 diff --git a/go.mod b/go.mod index e21eafb..3f45e39 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,10 @@ require ( github.com/fsnotify/fsnotify v1.7.0 github.com/gin-gonic/gin v1.10.0 github.com/golang-jwt/jwt/v5 v5.2.1 - github.com/redis/go-redis/v9 v9.5.3 + github.com/redis/go-redis/v9 v9.5.4 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 + github.com/ulule/limiter/v3 v3.11.2 github.com/urfave/cli/v2 v2.27.2 golang.org/x/crypto v0.25.0 gorm.io/driver/mysql v1.5.7 @@ -78,6 +79,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index e237057..9180ab4 100644 --- a/go.sum +++ b/go.sum @@ -156,11 +156,15 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU= github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.5.4 h1:vOFYDKKVgrI5u++QvnMT7DksSMYg7Aw/Np4vLJLKLwY= +github.com/redis/go-redis/v9 v9.5.4/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -200,6 +204,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= +github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI= github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= diff --git a/internal/middleware/cache/ip_limiter.go b/internal/middleware/cache/ip_limiter.go index bef2c7b..4cf8438 100644 --- a/internal/middleware/cache/ip_limiter.go +++ b/internal/middleware/cache/ip_limiter.go @@ -1,45 +1,26 @@ package cache import ( - "fmt" "time" "github.com/TensoRaws/NuxBT-Backend/module/cache" "github.com/TensoRaws/NuxBT-Backend/module/log" - "github.com/TensoRaws/NuxBT-Backend/module/util" "github.com/gin-gonic/gin" - "github.com/redis/go-redis/v9" + "github.com/ulule/limiter/v3" + mgin "github.com/ulule/limiter/v3/drivers/middleware/gin" + redisLimiter "github.com/ulule/limiter/v3/drivers/store/redis" ) -func NewRateLimiter(redisClient *cache.Client, key string, limit int, slidingWindow time.Duration) gin.HandlerFunc { - _, err := redisClient.Ping().Result() +func NewRateLimiter(redisClient *cache.Client, limit int, slidingWindow time.Duration) gin.HandlerFunc { + rate := limiter.Rate{ + Period: slidingWindow, + Limit: int64(limit), + } + store, err := redisLimiter.NewStore(redisClient.C) if err != nil { - panic(fmt.Sprint("error init redis", err.Error())) + log.Logger.Error(err) } + l := limiter.New(store, rate, limiter.WithClientIPHeader("True-Client-IP")) - return func(c *gin.Context) { - now := time.Now().UnixNano() - log.Logger.Infof("-------------------> path: %v", c.Request.URL.Path) - userCntKey := fmt.Sprint(c.ClientIP(), ":", key, ":", c.Request.URL.Path) - - _, err := redisClient.ZRemRangeByScore(userCntKey, - "0", - fmt.Sprint(now-(slidingWindow.Nanoseconds()))).Result() - if err != nil { - log.Logger.Error(err) - return - } - - reqs, _ := redisClient.ZRange(userCntKey, 0, -1).Result() - - if len(reqs) >= limit { - util.AbortWithMsg(c, "Too many request...") - log.Logger.Warnf("------------------> too many request, key: %v", userCntKey) - return - } - - c.Next() - redisClient.ZAddNX(userCntKey, redis.Z{Score: float64(now), Member: float64(now)}) - redisClient.Expire(userCntKey, slidingWindow) - } + return mgin.NewMiddleware(l) } diff --git a/internal/router/api/v1/api.go b/internal/router/api/v1/api.go index 33e6a1d..b343b7f 100644 --- a/internal/router/api/v1/api.go +++ b/internal/router/api/v1/api.go @@ -17,7 +17,7 @@ func NewAPI() *gin.Engine { r := gin.New() r.Use(logger.DefaultLogger(), gin.Recovery()) // 日志中间件 r.Use(middleware_cache.NewRateLimiter( - middleware_cache.Clients[cache.IPLimit], "general", config.ServerConfig.RequestLimit, 60*time.Second)) + cache.Clients[cache.IPLimit], config.ServerConfig.RequestLimit, 60*time.Second)) r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ diff --git a/internal/middleware/cache/cache.go b/module/cache/cache.go similarity index 71% rename from internal/middleware/cache/cache.go rename to module/cache/cache.go index 0a964dc..83cea8f 100644 --- a/internal/middleware/cache/cache.go +++ b/module/cache/cache.go @@ -4,15 +4,14 @@ import ( "bytes" "sync" - "github.com/TensoRaws/NuxBT-Backend/module/cache" "github.com/gin-gonic/gin" ) var once sync.Once -var Clients = map[cache.RDB]*cache.Client{ - cache.IPLimit: {}, - cache.User: {}, +var Clients = map[RDB]*Client{ + IPLimit: {}, + User: {}, } type responseWriter struct { @@ -29,6 +28,6 @@ func (w responseWriter) Write(b []byte) (int, error) { func Init() { once.Do(func() { - cache.NewRedisClients(Clients) + NewRedisClients(Clients) }) } diff --git a/module/cache/redis.go b/module/cache/redis.go index dd73815..ebe0a5a 100644 --- a/module/cache/redis.go +++ b/module/cache/redis.go @@ -44,8 +44,6 @@ func NewRedisClient(n int) *Client { return &Client{C: r, Ctx: ctx} } -// 封装常用接口 - // ClientGetName returns the name of the connection. func (c Client) ClientGetName() *redis.StringCmd { return c.C.ClientGetName(c.Ctx)