mirror of
https://github.com/WJQSERVER-STUDIO/ghproxy.git
synced 2026-02-03 00:01:10 +08:00
24w24a
This commit is contained in:
parent
0ce5c2c11c
commit
32584f9516
10 changed files with 97 additions and 10 deletions
20
CHANGELOG.md
20
CHANGELOG.md
|
|
@ -1,5 +1,25 @@
|
|||
# 更新日志
|
||||
|
||||
24w24a
|
||||
---
|
||||
- PRE-RELEASE: 此版本是v1.7.5的预发布版本,请勿在生产环境中使用
|
||||
- ADD: `Rate`模块加入`IP`速率限制,可限制单个IP的请求速率
|
||||
- CHANGE: 处理积攒的依赖库更新,更新如下依赖库:
|
||||
- **github.com/gabriel-vasile/mimetype**: 从 v1.4.6 升级到 v1.4.7
|
||||
- **github.com/go-playground/validator/v10**: 从 v10.22.1 升级到 v10.23.0
|
||||
- **github.com/klauspost/cpuid/v2**: 从 v2.2.8 升级到 v2.2.9
|
||||
- **github.com/onsi/ginkgo/v2**: 从 v2.21.0 升级到 v2.22.0
|
||||
- **golang.org/x/arch**: 从 v0.11.0 升级到 v0.12.0
|
||||
- **golang.org/x/crypto**: 从 v0.28.0 升级到 v0.29.0
|
||||
- **golang.org/x/exp**: 从 v0.0.0-20241009180824-f66d83c29e7c 升级到 v0.0.0-20241108190413-2d47ceb2692f
|
||||
- **golang.org/x/mod**: 从 v0.21.0 升级到 v0.22.0
|
||||
- **golang.org/x/net**: 从 v0.30.0 升级到 v0.31.0
|
||||
- **golang.org/x/sync**: 从 v0.8.0 升级到 v0.9.0
|
||||
- **golang.org/x/sys**: 从 v0.26.0 升级到 v0.27.0
|
||||
- **golang.org/x/text**: 从 v0.19.0 升级到 v0.20.0
|
||||
- **golang.org/x/tools**: 从 v0.26.0 升级到 v0.27.0
|
||||
- **google.golang.org/protobuf**: 从 v1.35.1 升级到 v1.35.2
|
||||
|
||||
v1.7.4
|
||||
---
|
||||
- CHANGE: 对二进制文件部署脚本进行优化
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ type WhitelistConfig struct {
|
|||
|
||||
type RateLimitConfig struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
RateMethod string `toml:"rateMethod"`
|
||||
RatePerMinute int `toml:"ratePerMinute"`
|
||||
Burst int `toml:"burst"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,5 +30,6 @@ whitelistFile = "/data/ghproxy/config/whitelist.json"
|
|||
|
||||
[rateLimit]
|
||||
enabled = false
|
||||
rateMrthod = "total" # "ip" or "total"
|
||||
ratePerMinute = 180
|
||||
burst = 5
|
||||
|
|
|
|||
|
|
@ -30,5 +30,6 @@ whitelistFile = "/usr/local/ghproxy/config/whitelist.json"
|
|||
|
||||
[rateLimit]
|
||||
enabled = false
|
||||
rateMrthod = "total" # "ip" or "total"
|
||||
ratePerMinute = 180
|
||||
burst = 5
|
||||
|
|
|
|||
|
|
@ -30,5 +30,6 @@ whitelistFile = "/data/ghproxy/config/whitelist.json"
|
|||
|
||||
[rateLimit]
|
||||
enabled = false
|
||||
rateMrthod = "total" # "ip" or "total"
|
||||
ratePerMinute = 180
|
||||
burst = 5
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -23,7 +23,7 @@ require (
|
|||
github.com/go-playground/validator/v10 v10.23.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 // indirect
|
||||
github.com/google/pprof v0.0.0-20241122213907-cbe949e5a41b // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -46,6 +46,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241122213907-cbe949e5a41b h1:SXO0REt4iu865upYCk8aKBBJQ4BqoE0ReP23ClMu60s=
|
||||
github.com/google/pprof v0.0.0-20241122213907-cbe949e5a41b/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
|
|
|
|||
11
main.go
11
main.go
|
|
@ -22,8 +22,9 @@ var (
|
|||
router *gin.Engine
|
||||
configfile = "/data/ghproxy/config/config.toml"
|
||||
cfgfile string
|
||||
limiter *rate.RateLimiter
|
||||
version string
|
||||
limiter *rate.RateLimiter
|
||||
iplimiter *rate.IPRateLimiter
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -68,7 +69,13 @@ func setupApi(cfg *config.Config, router *gin.Engine, version string) {
|
|||
|
||||
func setupRateLimit(cfg *config.Config) {
|
||||
if cfg.RateLimit.Enabled {
|
||||
if cfg.RateLimit.RateMethod == "ip" {
|
||||
iplimiter = rate.NewIPRateLimiter(cfg.RateLimit.RatePerMinute, cfg.RateLimit.Burst, 1*time.Minute)
|
||||
} else if cfg.RateLimit.RateMethod == "total" {
|
||||
limiter = rate.New(cfg.RateLimit.RatePerMinute, cfg.RateLimit.Burst, 1*time.Minute)
|
||||
} else {
|
||||
logError("Invalid RateLimit Method: %s", cfg.RateLimit.RateMethod)
|
||||
}
|
||||
logInfo("Rate Limit Loaded")
|
||||
}
|
||||
}
|
||||
|
|
@ -106,7 +113,7 @@ func init() {
|
|||
}
|
||||
|
||||
router.NoRoute(func(c *gin.Context) {
|
||||
proxy.NoRouteHandler(cfg, limiter)(c)
|
||||
proxy.NoRouteHandler(cfg, limiter, iplimiter)(c)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,12 +33,24 @@ var exps = []*regexp.Regexp{
|
|||
regexp.MustCompile(`^(?:https?://)?gist\.github(?:usercontent|)\.com/([^/]+)/.+?/.+`),
|
||||
}
|
||||
|
||||
func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter) gin.HandlerFunc {
|
||||
func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *rate.IPRateLimiter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 限制访问频率
|
||||
if cfg.RateLimit.Enabled {
|
||||
logInfo("Rate_Limit Enabled")
|
||||
if !limiter.Allow() {
|
||||
|
||||
var allowed bool
|
||||
|
||||
switch cfg.RateLimit.RateMethod {
|
||||
case "ip":
|
||||
allowed = iplimiter.Allow(c.ClientIP())
|
||||
case "total":
|
||||
allowed = limiter.Allow()
|
||||
default:
|
||||
logWarning("Invalid RateLimit Method")
|
||||
return
|
||||
}
|
||||
|
||||
if !allowed {
|
||||
c.JSON(http.StatusTooManyRequests, gin.H{"error": "Too Many Requests"})
|
||||
logWarning("%s %s %s %s %s 429-TooManyRequests", c.ClientIP(), c.Request.Method, c.Request.URL.RequestURI(), c.Request.Header.Get("User-Agent"), c.Request.Proto)
|
||||
return
|
||||
|
|
|
|||
42
rate/rate.go
42
rate/rate.go
|
|
@ -1,15 +1,33 @@
|
|||
package rate
|
||||
|
||||
import (
|
||||
"ghproxy/logger"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
// 日志输出
|
||||
var (
|
||||
logw = logger.Logw
|
||||
logInfo = logger.LogInfo
|
||||
logWarning = logger.LogWarning
|
||||
logError = logger.LogError
|
||||
)
|
||||
|
||||
// 总体限流器
|
||||
type RateLimiter struct {
|
||||
limiter *rate.Limiter
|
||||
}
|
||||
|
||||
// 基于IP的限流器
|
||||
type IPRateLimiter struct {
|
||||
limiters map[string]*RateLimiter
|
||||
limit int
|
||||
burst int
|
||||
duration time.Duration
|
||||
}
|
||||
|
||||
func New(limit int, burst int, duration time.Duration) *RateLimiter {
|
||||
return &RateLimiter{
|
||||
limiter: rate.NewLimiter(rate.Limit(float64(limit)/duration.Seconds()), burst),
|
||||
|
|
@ -19,3 +37,27 @@ func New(limit int, burst int, duration time.Duration) *RateLimiter {
|
|||
func (rl *RateLimiter) Allow() bool {
|
||||
return rl.limiter.Allow()
|
||||
}
|
||||
|
||||
func NewIPRateLimiter(limit int, burst int, duration time.Duration) *IPRateLimiter {
|
||||
return &IPRateLimiter{
|
||||
limiters: make(map[string]*RateLimiter),
|
||||
limit: limit,
|
||||
burst: burst,
|
||||
duration: duration,
|
||||
}
|
||||
}
|
||||
|
||||
func (rl *IPRateLimiter) Allow(ip string) bool {
|
||||
if ip == "" {
|
||||
logWarning("empty ip")
|
||||
return false
|
||||
}
|
||||
|
||||
limiter, ok := rl.limiters[ip]
|
||||
if !ok {
|
||||
// 创建新的 RateLimiter 并存储
|
||||
limiter = New(rl.limit, rl.burst, rl.duration)
|
||||
rl.limiters[ip] = limiter
|
||||
}
|
||||
return limiter.Allow()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue