Merge pull request #54 from WJQSERVER-STUDIO/dev

This commit is contained in:
WJQSERVER 2025-02-28 20:06:27 +08:00 committed by GitHub
commit 60a1f6073d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 189 additions and 29 deletions

View file

@ -1,5 +1,18 @@
# 更新日志
2.3.1
---
- CHANGE: 改进`Pages``External`模式下的路由
- CHANGE: 使用`H2C` bool 代替 `enableH2C` string (2.4.0 弃用 `enableH2C`)
- CHANGE: 使用`Mode` string 代替`Pages`内的 `enable` bool (2.4.0 弃用 `enable`)
25w15a
---
- PRE-RELEASE: 此版本是v2.3.1的预发布版本,请勿在生产环境中使用;
- CHANGE: 改进`Pages``External`模式下的路由
- CHANGE: 使用`H2C` bool 代替 `enableH2C` string (2.4.0 弃用 `enableH2C`)
- CHANGE: 使用`Mode` string 代替`Pages`内的 `enable` bool (2.4.0 弃用 `enable`)
2.3.0
---
- CHANGE: 使用`touka-httpc`封装`HTTP Client`, 更新到`v0.2.0`版本, 参看`touka-httpc`

View file

@ -1 +1 @@
25w14b
25w15a

View file

@ -93,7 +93,8 @@ wget -O install-dev.sh https://raw.githubusercontent.com/WJQSERVER-STUDIO/ghprox
host = "0.0.0.0" # 监听地址
port = 8080 # 监听端口
sizeLimit = 125 # 125MB
enableH2C = "on" # 是否开启H2C传输(latest和dev版本请开启) on/off
H2C = true # 是否开启H2C传输
enableH2C = "on" # 是否开启H2C传输(latest和dev版本请开启) on/off (2.4.0弃用)
[httpc]
mode = "auto" # "auto" or "advanced" HTTP客户端模式 自动/高级模式
@ -102,7 +103,8 @@ maxIdleConnsPerHost = 60 # only for advanced mode 仅用于高级模式
maxConnsPerHost = 0 # only for advanced mode 仅用于高级模式
[pages]
enabled = false # 是否开启外置静态页面(Docker版本请关闭此项)
mode = "internal" # "internal" or "external" 内部/外部 前端 默认内部
enabled = false # 是否开启外置静态页面(Docker版本请关闭此项) (2.4.0弃用)
theme = "bootstrap" # "bootstrap" or "nebula" 内置主题
staticPath = "/data/www" # 静态页面文件路径

View file

@ -1 +1 @@
2.3.0
2.3.1

View file

@ -17,10 +17,20 @@ type Config struct {
Outbound OutboundConfig
}
/*
[server]
host = "0.0.0.0" # 监听地址
port = 8080 # 监听端口
sizeLimit = 125 # 125MB
H2C = true # 是否开启H2C传输
enableH2C = "on" # 是否开启H2C传输(latest和dev版本请开启) on/off (2.4.0弃用)
*/
type ServerConfig struct {
Port int `toml:"port"`
Host string `toml:"host"`
SizeLimit int `toml:"sizeLimit"`
H2C bool `toml:"H2C"`
EnableH2C string `toml:"enableH2C"`
Debug bool `toml:"debug"`
}
@ -41,11 +51,13 @@ type HttpcConfig struct {
/*
[pages]
mode = "internal" # "internal" or "external"
enabled = false
theme = "bootstrap" # "bootstrap" or "nebula"
staticDir = "/data/www"
*/
type PagesConfig struct {
Mode string `toml:"mode"`
Enabled bool `toml:"enabled"`
Theme string `toml:"theme"`
StaticDir string `toml:"staticDir"`

View file

@ -2,6 +2,7 @@
host = "0.0.0.0"
port = 8080
sizeLimit = 125 # MB
H2C = true
enableH2C = "on" # "on" or "off"
debug = false
@ -12,6 +13,7 @@ maxIdleConnsPerHost = 60 # only for advanced mode
maxConnsPerHost = 0 # only for advanced mode
[pages]
mode = "internal" # "internal" or "external"
enabled = false
theme = "bootstrap" # "bootstrap" or "nebula"
staticDir = "/data/www"

View file

@ -2,6 +2,7 @@
host = "127.0.0.1"
port = 8080
sizeLimit = 125 # MB
H2C = true
enableH2C = "on"
debug = false
@ -12,6 +13,7 @@ maxIdleConnsPerHost = 60 # only for advanced mode
maxConnsPerHost = 0 # only for advanced mode
[pages]
mode = "internal" # "internal" or "external"
enabled = false
theme = "bootstrap" # "bootstrap" or "nebula"
staticDir = "/usr/local/ghproxy/pages"

8
go.mod
View file

@ -4,7 +4,7 @@ go 1.24.0
require (
github.com/BurntSushi/toml v1.4.0
github.com/WJQSERVER-STUDIO/go-utils/logger v1.3.0
github.com/WJQSERVER-STUDIO/go-utils/logger v1.4.0
github.com/gin-gonic/gin v1.10.0
github.com/satomitouka/touka-httpc v0.2.0
golang.org/x/net v0.35.0
@ -12,7 +12,7 @@ require (
)
require (
github.com/bytedance/sonic v1.12.8 // indirect
github.com/bytedance/sonic v1.12.9 // indirect
github.com/bytedance/sonic/loader v0.2.3 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
@ -23,7 +23,7 @@ require (
github.com/goccy/go-json v0.10.5 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@ -32,7 +32,7 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.14.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect

16
go.sum
View file

@ -1,9 +1,9 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/WJQSERVER-STUDIO/go-utils/logger v1.3.0 h1:rOvutC4zYfvtSGN2CNZrycjtq8dLpfu7ypy7tTEErPY=
github.com/WJQSERVER-STUDIO/go-utils/logger v1.3.0/go.mod h1:oW884JCCPDU6c906LI0uKXndWLiRvjb9LkGYC2cqRO8=
github.com/bytedance/sonic v1.12.8 h1:4xYRVRlXIgvSZ4e8iVTlMF5szgpXd4AfvuWgA8I8lgs=
github.com/bytedance/sonic v1.12.8/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
github.com/WJQSERVER-STUDIO/go-utils/logger v1.4.0 h1:pbtKxDHM3jUWZYfCT5BJqToAm5VQUp8mT2t6XTiYdRg=
github.com/WJQSERVER-STUDIO/go-utils/logger v1.4.0/go.mod h1:oW884JCCPDU6c906LI0uKXndWLiRvjb9LkGYC2cqRO8=
github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ=
github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
@ -35,8 +35,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
@ -71,8 +71,8 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

131
main.go
View file

@ -106,6 +106,78 @@ func InitReq(cfg *config.Config) {
proxy.InitReq(cfg)
}
// loadEmbeddedPages 加载嵌入式页面资源
func loadEmbeddedPages(cfg *config.Config) (fs.FS, error) {
var pages fs.FS
var err error
switch cfg.Pages.Theme {
case "bootstrap":
pages, err = fs.Sub(pagesFS, "pages/bootstrap")
case "nebula":
pages, err = fs.Sub(NebulaPagesFS, "pages/nebula")
default:
pages, err = fs.Sub(pagesFS, "pages/bootstrap") // 默认主题
logWarning("Invalid Pages Theme: %s, using default theme 'bootstrap'", cfg.Pages.Theme)
}
if err != nil {
return nil, fmt.Errorf("failed to load embedded pages: %w", err)
}
return pages, nil
}
// setupPages 设置页面路由
func setupPages(cfg *config.Config, router *gin.Engine) {
switch cfg.Pages.Mode {
case "internal":
// 加载嵌入式资源
pages, err := loadEmbeddedPages(cfg)
if err != nil {
logError("Failed when processing internal pages: %s", err)
return
}
// 设置嵌入式资源路由
router.GET("/", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/favicon.ico", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/script.js", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/style.css", gin.WrapH(http.FileServer(http.FS(pages))))
case "external":
// 设置外部资源路径
indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir)
faviconPath := fmt.Sprintf("%s/favicon.ico", cfg.Pages.StaticDir)
javascriptsPath := fmt.Sprintf("%s/script.js", cfg.Pages.StaticDir)
stylesheetsPath := fmt.Sprintf("%s/style.css", cfg.Pages.StaticDir)
// 设置外部资源路由
router.GET("/", func(c *gin.Context) {
c.File(indexPagePath)
logInfo("IP:%s UA:%s METHOD:%s HTTPv:%s", c.ClientIP(), c.Request.UserAgent(), c.Request.Method, c.Request.Proto)
})
router.StaticFile("/favicon.ico", faviconPath)
router.StaticFile("/script.js", javascriptsPath)
router.StaticFile("/style.css", stylesheetsPath)
default:
// 处理无效的Pages Mode
logWarning("Invalid Pages Mode: %s, using default embedded theme", cfg.Pages.Mode)
// 加载嵌入式资源
pages, err := loadEmbeddedPages(cfg)
if err != nil {
logError("Failed when processing pages: %s", err)
return
}
// 设置嵌入式资源路由
router.GET("/", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/favicon.ico", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/script.js", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/style.css", gin.WrapH(http.FileServer(http.FS(pages))))
}
}
func init() {
readFlag()
flag.Parse()
@ -142,6 +214,10 @@ func init() {
router.Use(timing.Middleware())
//H2C默认值为true而后遵循cfg.Server.EnableH2C的设置
if cfg.Server.H2C {
router.UseH2C = true
} else {
logWarning("cfg.Server.EnableH2C 将于2.4.0弃用请使用cfg.Server.H2C")
if cfg.Server.EnableH2C == "on" {
router.UseH2C = true
} else if cfg.Server.EnableH2C == "" {
@ -149,17 +225,69 @@ func init() {
} else {
router.UseH2C = false
}
}
/*
// (2.4.0启用)
if cfg.Server.H2C {
router.UseH2C = true
}
*/
setupApi(cfg, router, version)
if cfg.Pages.Enabled {
// setupPages(cfg, router) // 2.4.0启用
logInfo("Pages Mode: %s", cfg.Pages.Mode)
if cfg.Pages.Mode == "internal" {
var pages fs.FS
var err error
if cfg.Pages.Theme == "bootstrap" {
pages, err = fs.Sub(pagesFS, "pages/bootstrap")
if err != nil {
logError("Failed when processing pages: %s", err)
}
} else if cfg.Pages.Theme == "nebula" {
pages, err = fs.Sub(NebulaPagesFS, "pages/nebula")
if err != nil {
logError("Failed when processing pages: %s", err)
}
} else {
pages, err = fs.Sub(pagesFS, "pages/bootstrap")
if err != nil {
logError("Failed when processing pages: %s", err)
}
}
router.GET("/", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/favicon.ico", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/script.js", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/style.css", gin.WrapH(http.FileServer(http.FS(pages))))
} else if cfg.Pages.Mode == "external" {
indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir)
faviconPath := fmt.Sprintf("%s/favicon.ico", cfg.Pages.StaticDir)
javascriptsPath := fmt.Sprintf("%s/script.js", cfg.Pages.StaticDir)
stylesheetsPath := fmt.Sprintf("%s/style.css", cfg.Pages.StaticDir)
router.GET("/", func(c *gin.Context) {
c.File(indexPagePath)
logInfo("IP:%s UA:%s METHOD:%s HTTPv:%s", c.ClientIP(), c.Request.UserAgent(), c.Request.Method, c.Request.Proto)
})
router.StaticFile("/favicon.ico", faviconPath)
router.StaticFile("/script.js", javascriptsPath)
router.StaticFile("/style.css", stylesheetsPath)
} else {
logWarning("缺少 cfg.Pages.Mode 配置, cfg.Pages.Enable 将于2.4.0弃用请使用cfg.Pages.Mode")
if cfg.Pages.Enabled {
indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir)
faviconPath := fmt.Sprintf("%s/favicon.ico", cfg.Pages.StaticDir)
javascriptsPath := fmt.Sprintf("%s/script.js", cfg.Pages.StaticDir)
stylesheetsPath := fmt.Sprintf("%s/style.css", cfg.Pages.StaticDir)
router.GET("/", func(c *gin.Context) {
c.File(indexPagePath)
logInfo("IP:%s UA:%s METHOD:%s HTTPv:%s", c.ClientIP(), c.Request.UserAgent(), c.Request.Method, c.Request.Proto)
})
router.StaticFile("/favicon.ico", faviconPath)
router.StaticFile("/script.js", javascriptsPath)
router.StaticFile("/style.css", stylesheetsPath)
} else if !cfg.Pages.Enabled {
var pages fs.FS
var err error
@ -184,6 +312,7 @@ func init() {
router.GET("/script.js", gin.WrapH(http.FileServer(http.FS(pages))))
router.GET("/style.css", gin.WrapH(http.FileServer(http.FS(pages))))
}
}
router.NoRoute(func(c *gin.Context) {
proxy.NoRouteHandler(cfg, limiter, iplimiter, runMode)(c)