Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbfc7c0d6d | ||
|
|
5af898b3e6 | ||
|
|
3c162bf9d7 | ||
|
|
1eed79463d | ||
|
|
6f67f6f5b4 | ||
|
|
2a5570a447 |
20
.github/workflows/build-dev.yml
vendored
20
.github/workflows/build-dev.yml
vendored
@@ -21,31 +21,35 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Load VERSION
|
||||
- name: 加载版本号
|
||||
run: |
|
||||
if [ -f DEV-VERSION ]; then
|
||||
echo "VERSION=$(cat DEV-VERSION)" >> $GITHUB_ENV
|
||||
else
|
||||
echo "DEV-VERSION file not found!" && exit 1
|
||||
fi
|
||||
- name: Set up Go
|
||||
- name: 安装 Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- name: Install UPX
|
||||
- name: 安装UPX
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install upx -y
|
||||
- name: Build
|
||||
- name: 编译
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
run: |
|
||||
CGO_ENABLED=0 go build -o ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./main.go
|
||||
CGO_ENABLED=0 go build -ldflags "-X main.version=${{ env.VERSION }}" -o ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./main.go
|
||||
upx -9 ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
|
||||
- name: Package
|
||||
- name: 打包
|
||||
run: |
|
||||
tar -czvf ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz ./${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}
|
||||
mkdir ghproxyd
|
||||
cp ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}} ./ghproxyd/
|
||||
cp LICENSE ./ghproxyd/
|
||||
tar -czf ${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz -C ghproxyd .
|
||||
ls
|
||||
- name: Upload to GitHub Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -57,7 +61,7 @@ jobs:
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ env.VERSION }}
|
||||
artifacts: ./${{ env.OUTPUT_BINARY }}*
|
||||
artifacts: ./${{ env.OUTPUT_BINARY }}-${{matrix.goos}}-${{matrix.goarch}}.tar.gz
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ env.VERSION }}
|
||||
allowUpdates: true
|
||||
|
||||
45
.github/workflows/build.yml
vendored
45
.github/workflows/build.yml
vendored
@@ -62,7 +62,8 @@ jobs:
|
||||
tag: ${{ env.VERSION }}
|
||||
allowUpdates: true
|
||||
env:
|
||||
export PATH: $PATH:/usr/local/go/bin
|
||||
export PATH: $PATH:/usr/local/go/bin
|
||||
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build # 确保这个作业在 build 作业完成后运行
|
||||
@@ -102,3 +103,45 @@ jobs:
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}:${{ env.VERSION }}
|
||||
${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
docker-nocache:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build # 确保这个作业在 build 作业完成后运行
|
||||
env:
|
||||
IMAGE_NAME: wjqserver/ghproxy # 定义镜像名称变量
|
||||
DOCKERFILE: docker/dockerfile/nocache/Dockerfile # 定义 Dockerfile 路径变量
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Load VERSION
|
||||
run: |
|
||||
if [ -f VERSION ]; then
|
||||
echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV
|
||||
else
|
||||
echo "VERSION file not found!" && exit 1
|
||||
fi
|
||||
- name: Wait for Compile
|
||||
run: sleep 300s
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: 构建镜像
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: ./${{ env.DOCKERFILE }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}:${{ env.VERSION }}-nocache
|
||||
${{ env.IMAGE_NAME }}:nocache
|
||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,5 +1,25 @@
|
||||
# 更新日志
|
||||
|
||||
24w21c
|
||||
---
|
||||
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||
- CHANGE: 对编译打包进行改进,此后不再提供独立可执行文件,请改为拉取`tar.gz`压缩包
|
||||
- CHANGE: 由于上述原因,对Docker打包进行相应改进
|
||||
|
||||
24w21b
|
||||
---
|
||||
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||
- ADD: 加入版本号标识与对应API接口
|
||||
- ADD: 加入速率限制API接口
|
||||
- CHANGE: 修改打包部分
|
||||
|
||||
24w21a
|
||||
---
|
||||
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||
- ADD: 尝试加入程序内置速率限制
|
||||
- CHANGE: 更新相关依赖库
|
||||
- CHANGE: 更换Dev版本底包,于release版本保持一致
|
||||
|
||||
v1.6.2
|
||||
---
|
||||
- CHANGE: 优化前端界面,优化部分样式
|
||||
|
||||
@@ -1 +1 @@
|
||||
24w20b
|
||||
24w21c
|
||||
26
api/api.go
26
api/api.go
@@ -13,7 +13,6 @@ var (
|
||||
cfg *config.Config
|
||||
)
|
||||
|
||||
// 日志模块
|
||||
var (
|
||||
logw = logger.Logw
|
||||
logInfo = logger.LogInfo
|
||||
@@ -21,8 +20,7 @@ var (
|
||||
logError = logger.LogError
|
||||
)
|
||||
|
||||
func InitHandleRouter(cfg *config.Config, router *gin.Engine) {
|
||||
// 设置路由
|
||||
func InitHandleRouter(cfg *config.Config, router *gin.Engine, version string) {
|
||||
apiRouter := router.Group("api")
|
||||
{
|
||||
apiRouter.GET("/size_limit", func(c *gin.Context) {
|
||||
@@ -40,6 +38,12 @@ func InitHandleRouter(cfg *config.Config, router *gin.Engine) {
|
||||
apiRouter.GET("/healthcheck", func(c *gin.Context) {
|
||||
HealthcheckHandler(c)
|
||||
})
|
||||
apiRouter.GET("/version", func(c *gin.Context) {
|
||||
VersionHandler(c, version)
|
||||
})
|
||||
apiRouter.GET("/rate_limit/status", func(c *gin.Context) {
|
||||
RateLimitStatusHandler(c, cfg)
|
||||
})
|
||||
}
|
||||
logInfo("API router Init success")
|
||||
}
|
||||
@@ -84,3 +88,19 @@ func HealthcheckHandler(c *gin.Context) {
|
||||
"Status": "OK",
|
||||
})
|
||||
}
|
||||
|
||||
func VersionHandler(c *gin.Context, version string) {
|
||||
logInfo("%s %s %s %s %s", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Request.Proto)
|
||||
c.Writer.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
|
||||
"Version": version,
|
||||
})
|
||||
}
|
||||
|
||||
func RateLimitStatusHandler(c *gin.Context, cfg *config.Config) {
|
||||
logInfo("%s %s %s %s %s", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Request.Proto)
|
||||
c.Writer.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
|
||||
"RateLimit": cfg.RateLimit.Enabled,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ type Config struct {
|
||||
Auth AuthConfig
|
||||
Blacklist BlacklistConfig
|
||||
Whitelist WhitelistConfig
|
||||
RateLimit RateLimitConfig
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
@@ -49,6 +50,12 @@ type WhitelistConfig struct {
|
||||
WhitelistFile string `toml:"whitelistFile"`
|
||||
}
|
||||
|
||||
type RateLimitConfig struct {
|
||||
Enabled bool `toml:"enabled"`
|
||||
RatePerMinute int `toml:"ratePerMinute"`
|
||||
Burst int `toml:"burst"`
|
||||
}
|
||||
|
||||
// LoadConfig 从 TOML 配置文件加载配置
|
||||
func LoadConfig(filePath string) (*Config, error) {
|
||||
var config Config
|
||||
|
||||
@@ -25,3 +25,8 @@ enabled = false
|
||||
[whitelist]
|
||||
enabled = false
|
||||
whitelistFile = "/data/ghproxy/config/whitelist.json"
|
||||
|
||||
[rateLimit]
|
||||
enabled = false
|
||||
ratePerMinute = 100
|
||||
burst = 10
|
||||
|
||||
@@ -96,7 +96,9 @@ VERSION=$(curl -s https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/mai
|
||||
wget -q -O ${ghproxy_dir}/VERSION https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghproxy/main/DEV-VERSION
|
||||
|
||||
# 下载ghproxy
|
||||
wget -q -O ${ghproxy_dir}/ghproxy https://github.com/WJQSERVER-STUDIO/ghproxy/releases/download/$VERSION/ghproxy-linux-$ARCH
|
||||
wget -q -O ${ghproxy_dir}/ghproxy https://github.com/WJQSERVER-STUDIO/ghproxy/releases/download/$VERSION/ghproxy-linux-$ARCH.tar.gz
|
||||
install tar
|
||||
tar -zxvf ${ghproxy_dir}/ghproxy-linux-$ARCH.tar.gz -C ${ghproxy_dir}
|
||||
chmod +x ${ghproxy_dir}/ghproxy
|
||||
|
||||
# 下载pages
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM wjqserver/caddy:daily-alpine AS builder
|
||||
FROM wjqserver/caddy:2.9.0-rc-alpine AS builder
|
||||
|
||||
ARG USER=WJQSERVER-STUDIO
|
||||
ARG REPO=ghproxy
|
||||
@@ -13,7 +13,7 @@ RUN mkdir -p /data/${APPLICATION}/config
|
||||
RUN mkdir -p /data/${APPLICATION}/log
|
||||
|
||||
# 安装依赖
|
||||
RUN apk add --no-cache curl wget
|
||||
RUN apk add --no-cache curl wget tar
|
||||
|
||||
# 前端
|
||||
RUN wget -O /data/www/index.html https://raw.githubusercontent.com/${USER}/${REPO}/main/pages/index.html
|
||||
@@ -21,7 +21,9 @@ RUN wget -O /data/www/favicon.ico https://raw.githubusercontent.com/${USER}/${RE
|
||||
|
||||
# 后端
|
||||
RUN VERSION=$(curl -s https://raw.githubusercontent.com/${USER}/${REPO}/main/DEV-VERSION) && \
|
||||
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}-${TARGETOS}-${TARGETARCH}
|
||||
wget -O /data/${APPLICATION}/${APPLICATION} https://github.com/${USER}/${REPO}/releases/download/$VERSION/${APPLICATION}-${TARGETOS}-${TARGETARCH}.tar.gz && \
|
||||
tar -zxvf /data/${APPLICATION}/${APPLICATION}-${TARGETOS}-${TARGETARCH}.tar.gz -C /data/${APPLICATION} && \
|
||||
rm -rf /data/${APPLICATION}/${APPLICATION}-${TARGETOS}-${TARGETARCH}.tar.gz
|
||||
RUN wget -O /usr/local/bin/init.sh https://raw.githubusercontent.com/${USER}/${REPO}/main/docker/dockerfile/dev/init.sh
|
||||
|
||||
# 拉取配置
|
||||
@@ -34,7 +36,7 @@ RUN wget -O /data/${APPLICATION}/whitelist.json https://raw.githubusercontent.co
|
||||
RUN chmod +x /data/${APPLICATION}/${APPLICATION}
|
||||
RUN chmod +x /usr/local/bin/init.sh
|
||||
|
||||
FROM wjqserver/caddy:daily-alpine
|
||||
FROM wjqserver/caddy:2.9.0-rc-alpine
|
||||
|
||||
COPY --from=builder /data/www /data/www
|
||||
COPY --from=builder /data/caddy /data/caddy
|
||||
|
||||
5
go.mod
5
go.mod
@@ -22,7 +22,7 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.22.1 // 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-20241023014458-598669927662 // indirect
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // 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
|
||||
@@ -32,7 +32,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.48.1 // indirect
|
||||
@@ -48,6 +48,7 @@ require (
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
7
go.sum
7
go.sum
@@ -50,6 +50,8 @@ github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jn
|
||||
github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsPdLHF5dNyxq3jOWwu9w9UyH5vA=
|
||||
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/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=
|
||||
@@ -76,8 +78,11 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@@ -132,6 +137,8 @@ golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
|
||||
20
main.go
20
main.go
@@ -5,12 +5,14 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"ghproxy/api"
|
||||
"ghproxy/auth"
|
||||
"ghproxy/config"
|
||||
"ghproxy/logger"
|
||||
"ghproxy/proxy"
|
||||
"ghproxy/rate"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -20,6 +22,8 @@ var (
|
||||
router *gin.Engine
|
||||
configfile = "/data/ghproxy/config/config.toml"
|
||||
cfgfile string
|
||||
limiter *rate.RateLimiter
|
||||
version string
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -58,8 +62,15 @@ func loadlist(cfg *config.Config) {
|
||||
auth.Init(cfg)
|
||||
}
|
||||
|
||||
func setupApi(cfg *config.Config, router *gin.Engine) {
|
||||
api.InitHandleRouter(cfg, router)
|
||||
func setupApi(cfg *config.Config, router *gin.Engine, version string) {
|
||||
api.InitHandleRouter(cfg, router, version)
|
||||
}
|
||||
|
||||
func setupRateLimit(cfg *config.Config) {
|
||||
if cfg.RateLimit.Enabled {
|
||||
limiter = rate.New(cfg.RateLimit.RatePerMinute, cfg.RateLimit.Burst, 1*time.Minute)
|
||||
logInfo("Rate Limit Loaded")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -68,13 +79,14 @@ func init() {
|
||||
loadConfig()
|
||||
setupLogger(cfg)
|
||||
loadlist(cfg)
|
||||
setupRateLimit(cfg)
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
router = gin.Default()
|
||||
router.UseH2C = true
|
||||
|
||||
setupApi(cfg, router)
|
||||
setupApi(cfg, router, version)
|
||||
|
||||
if cfg.Pages.Enabled {
|
||||
indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir)
|
||||
@@ -92,7 +104,7 @@ func init() {
|
||||
}
|
||||
|
||||
router.NoRoute(func(c *gin.Context) {
|
||||
proxy.NoRouteHandler(cfg)(c)
|
||||
proxy.NoRouteHandler(cfg, limiter)(c)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 80%;
|
||||
max-width: 65%;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"ghproxy/auth"
|
||||
"ghproxy/config"
|
||||
"ghproxy/logger"
|
||||
"ghproxy/rate"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/imroc/req/v3"
|
||||
@@ -32,8 +33,17 @@ var exps = []*regexp.Regexp{
|
||||
regexp.MustCompile(`^(?:https?://)?gist\.github(?:usercontent|)\.com/([^/]+)/.+?/.+`),
|
||||
}
|
||||
|
||||
func NoRouteHandler(cfg *config.Config) gin.HandlerFunc {
|
||||
func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 限制访问频率
|
||||
if cfg.RateLimit.Enabled {
|
||||
if !limiter.Allow() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
rawPath := strings.TrimPrefix(c.Request.URL.RequestURI(), "/")
|
||||
re := regexp.MustCompile(`^(http:|https:)?/?/?(.*)`)
|
||||
matches := re.FindStringSubmatch(rawPath)
|
||||
|
||||
21
rate/rate.go
Normal file
21
rate/rate.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package rate
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
type RateLimiter struct {
|
||||
limiter *rate.Limiter
|
||||
}
|
||||
|
||||
func New(limit int, burst int, duration time.Duration) *RateLimiter {
|
||||
return &RateLimiter{
|
||||
limiter: rate.NewLimiter(rate.Limit(float64(limit)/duration.Seconds()), burst),
|
||||
}
|
||||
}
|
||||
|
||||
func (rl *RateLimiter) Allow() bool {
|
||||
return rl.limiter.Allow()
|
||||
}
|
||||
Reference in New Issue
Block a user