From 11c34459ca1f259b5aeda38de53934d12696dcb7 Mon Sep 17 00:00:00 2001 From: user123 Date: Mon, 26 Jan 2026 23:06:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=A6=81=E7=94=A8=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E9=9D=99=E6=80=81=E6=96=87=E4=BB=B6=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.toml | 1 + src/config/config.go | 32 ++++++---- src/handlers/github.go | 2 +- src/main.go | 129 +++++++++++++++++++++++---------------- src/utils/proxy_shell.go | 2 +- 5 files changed, 99 insertions(+), 67 deletions(-) diff --git a/src/config.toml b/src/config.toml index 18e8c2d..eb3813f 100644 --- a/src/config.toml +++ b/src/config.toml @@ -6,6 +6,7 @@ port = 5000 fileSize = 2147483648 # HTTP/2 多路复用 enableH2C = false +enableFrontend = true [rateLimit] # 每个IP每周期允许的请求数 diff --git a/src/config/config.go b/src/config/config.go index ceaf9de..f0f6e41 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -22,10 +22,11 @@ type RegistryMapping struct { // AppConfig 应用配置结构体 type AppConfig struct { Server struct { - Host string `toml:"host"` - Port int `toml:"port"` - FileSize int64 `toml:"fileSize"` - EnableH2C bool `toml:"enableH2C"` + Host string `toml:"host"` + Port int `toml:"port"` + FileSize int64 `toml:"fileSize"` + EnableH2C bool `toml:"enableH2C"` + EnableFrontend bool `toml:"enableFrontend"` } `toml:"server"` RateLimit struct { @@ -70,15 +71,17 @@ var ( func DefaultConfig() *AppConfig { return &AppConfig{ Server: struct { - Host string `toml:"host"` - Port int `toml:"port"` - FileSize int64 `toml:"fileSize"` - EnableH2C bool `toml:"enableH2C"` + Host string `toml:"host"` + Port int `toml:"port"` + FileSize int64 `toml:"fileSize"` + EnableH2C bool `toml:"enableH2C"` + EnableFrontend bool `toml:"enableFrontend"` }{ - Host: "0.0.0.0", - Port: 5000, - FileSize: 2 * 1024 * 1024 * 1024, // 2GB - EnableH2C: false, // 默认关闭H2C + Host: "0.0.0.0", + Port: 5000, + FileSize: 2 * 1024 * 1024 * 1024, + EnableH2C: false, + EnableFrontend: true, }, RateLimit: struct { RequestLimit int `toml:"requestLimit"` @@ -227,6 +230,11 @@ func overrideFromEnv(cfg *AppConfig) { cfg.Server.EnableH2C = enable } } + if val := os.Getenv("ENABLE_FRONTEND"); val != "" { + if enable, err := strconv.ParseBool(val); err == nil { + cfg.Server.EnableFrontend = enable + } + } if val := os.Getenv("MAX_FILE_SIZE"); val != "" { if size, err := strconv.ParseInt(val, 10, 64); err == nil && size > 0 { cfg.Server.FileSize = size diff --git a/src/handlers/github.go b/src/handlers/github.go index 8697118..2c45868 100644 --- a/src/handlers/github.go +++ b/src/handlers/github.go @@ -129,7 +129,7 @@ func proxyGitHubWithRedirect(c *gin.Context, u string, redirectCount int) { fmt.Printf("关闭响应体失败: %v\n", err) } }() - + // 检查并处理被阻止的内容类型 if c.Request.Method == "GET" { if contentType := resp.Header.Get("Content-Type"); blockedContentTypes[strings.ToLower(strings.Split(contentType, ";")[0])] { diff --git a/src/main.go b/src/main.go index 8465a64..07c25bc 100644 --- a/src/main.go +++ b/src/main.go @@ -40,6 +40,80 @@ var ( serviceStartTime = time.Now() ) +func buildRouter(cfg *config.AppConfig) *gin.Engine { + gin.SetMode(gin.ReleaseMode) + router := gin.Default() + + // 全局Panic恢复保护 + router.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) { + log.Printf("🚨 Panic recovered: %v", recovered) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Internal server error", + "code": "INTERNAL_ERROR", + }) + })) + + // 全局限流中间件 + router.Use(utils.RateLimitMiddleware(globalLimiter)) + + // 初始化监控端点 + initHealthRoutes(router) + + // 初始化镜像tar下载路由 + handlers.InitImageTarRoutes(router) + + if cfg.Server.EnableFrontend { + router.GET("/", func(c *gin.Context) { + serveEmbedFile(c, "public/index.html") + }) + router.GET("/public/*filepath", func(c *gin.Context) { + filepath := strings.TrimPrefix(c.Param("filepath"), "/") + serveEmbedFile(c, "public/"+filepath) + }) + + router.GET("/images.html", func(c *gin.Context) { + serveEmbedFile(c, "public/images.html") + }) + router.GET("/search.html", func(c *gin.Context) { + serveEmbedFile(c, "public/search.html") + }) + router.GET("/favicon.ico", func(c *gin.Context) { + serveEmbedFile(c, "public/favicon.ico") + }) + } else { + router.GET("/", func(c *gin.Context) { + c.Status(http.StatusNotFound) + }) + router.GET("/public/*filepath", func(c *gin.Context) { + c.Status(http.StatusNotFound) + }) + router.GET("/images.html", func(c *gin.Context) { + c.Status(http.StatusNotFound) + }) + router.GET("/search.html", func(c *gin.Context) { + c.Status(http.StatusNotFound) + }) + router.GET("/favicon.ico", func(c *gin.Context) { + c.Status(http.StatusNotFound) + }) + } + + // 注册dockerhub搜索路由 + handlers.RegisterSearchRoute(router) + + // 注册Docker认证路由 + router.Any("/token", handlers.ProxyDockerAuthGin) + router.Any("/token/*path", handlers.ProxyDockerAuthGin) + + // 注册Docker Registry代理路由 + router.Any("/v2/*path", handlers.ProxyDockerRegistryGin) + + // 注册GitHub代理路由(NoRoute处理器) + router.NoRoute(handlers.GitHubProxyHandler) + + return router +} + func main() { // 加载配置 if err := config.LoadConfig(); err != nil { @@ -62,60 +136,9 @@ func main() { // 初始化防抖器 handlers.InitDebouncer() - gin.SetMode(gin.ReleaseMode) - router := gin.Default() - - // 全局Panic恢复保护 - router.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) { - log.Printf("🚨 Panic recovered: %v", recovered) - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "Internal server error", - "code": "INTERNAL_ERROR", - }) - })) - - // 全局限流中间件 - router.Use(utils.RateLimitMiddleware(globalLimiter)) - - // 初始化监控端点 - initHealthRoutes(router) - - // 初始化镜像tar下载路由 - handlers.InitImageTarRoutes(router) - - // 静态文件路由 - router.GET("/", func(c *gin.Context) { - serveEmbedFile(c, "public/index.html") - }) - router.GET("/public/*filepath", func(c *gin.Context) { - filepath := strings.TrimPrefix(c.Param("filepath"), "/") - serveEmbedFile(c, "public/"+filepath) - }) - - router.GET("/images.html", func(c *gin.Context) { - serveEmbedFile(c, "public/images.html") - }) - router.GET("/search.html", func(c *gin.Context) { - serveEmbedFile(c, "public/search.html") - }) - router.GET("/favicon.ico", func(c *gin.Context) { - serveEmbedFile(c, "public/favicon.ico") - }) - - // 注册dockerhub搜索路由 - handlers.RegisterSearchRoute(router) - - // 注册Docker认证路由 - router.Any("/token", handlers.ProxyDockerAuthGin) - router.Any("/token/*path", handlers.ProxyDockerAuthGin) - - // 注册Docker Registry代理路由 - router.Any("/v2/*path", handlers.ProxyDockerRegistryGin) - - // 注册GitHub代理路由(NoRoute处理器) - router.NoRoute(handlers.GitHubProxyHandler) - cfg := config.GetConfig() + router := buildRouter(cfg) + fmt.Printf("HubProxy 启动成功\n") fmt.Printf("监听地址: %s:%d\n", cfg.Server.Host, cfg.Server.Port) fmt.Printf("限流配置: %d请求/%g小时\n", cfg.RateLimit.RequestLimit, cfg.RateLimit.PeriodHours) diff --git a/src/utils/proxy_shell.go b/src/utils/proxy_shell.go index 93d4982..9d82d93 100644 --- a/src/utils/proxy_shell.go +++ b/src/utils/proxy_shell.go @@ -104,4 +104,4 @@ func transformURL(url, host string) string { host = strings.TrimSuffix(host, "/") return host + "/" + url -} \ No newline at end of file +}