From ad9cffe9e204da0f5e00433e589c542e6d7b2a2b Mon Sep 17 00:00:00 2001 From: wjqserver <114663932+WJQSERVER@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:04:08 +0800 Subject: [PATCH] 25w15a --- CHANGELOG.md | 7 ++ DEV-VERSION | 2 +- README.md | 6 +- config/config.go | 12 ++++ config/config.toml | 2 + deploy/config.toml | 2 + go.mod | 8 +-- go.sum | 16 ++--- main.go | 155 +++++++++++++++++++++++++++++++++++++++++---- 9 files changed, 182 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e27e49..ab9b669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # 更新日志 +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` diff --git a/DEV-VERSION b/DEV-VERSION index 3db6a63..0fb0a68 100644 --- a/DEV-VERSION +++ b/DEV-VERSION @@ -1 +1 @@ -25w14b \ No newline at end of file +25w15a \ No newline at end of file diff --git a/README.md b/README.md index 6383e64..aae64b8 100644 --- a/README.md +++ b/README.md @@ -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" # 静态页面文件路径 diff --git a/config/config.go b/config/config.go index de887ce..75be98e 100644 --- a/config/config.go +++ b/config/config.go @@ -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"` diff --git a/config/config.toml b/config/config.toml index 919bcb8..04204b1 100644 --- a/config/config.toml +++ b/config/config.toml @@ -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" diff --git a/deploy/config.toml b/deploy/config.toml index 8f80a32..e72ad15 100644 --- a/deploy/config.toml +++ b/deploy/config.toml @@ -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" diff --git a/go.mod b/go.mod index f739c4e..6ee6a4b 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 7c6bb67..407c49b 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/main.go b/main.go index cc2eecc..79ce710 100644 --- a/main.go +++ b/main.go @@ -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,25 +214,32 @@ func init() { router.Use(timing.Middleware()) //H2C默认值为true,而后遵循cfg.Server.EnableH2C的设置 - if cfg.Server.EnableH2C == "on" { - router.UseH2C = true - } else if cfg.Server.EnableH2C == "" { + if cfg.Server.H2C { router.UseH2C = true } else { - router.UseH2C = false + logWarning("cfg.Server.EnableH2C 将于2.4.0弃用,请使用cfg.Server.H2C") + if cfg.Server.EnableH2C == "on" { + router.UseH2C = true + } else if cfg.Server.EnableH2C == "" { + router.UseH2C = true + } else { + router.UseH2C = false + } } + /* + // (2.4.0启用) + if cfg.Server.H2C { + router.UseH2C = true + } + */ + setupApi(cfg, router, version) - if cfg.Pages.Enabled { - indexPagePath := fmt.Sprintf("%s/index.html", cfg.Pages.StaticDir) - faviconPath := fmt.Sprintf("%s/favicon.ico", 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) - } else 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" { @@ -183,6 +262,56 @@ func init() { 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 + 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)))) + } } router.NoRoute(func(c *gin.Context) {