| |
| package main |
|
|
| import ( |
| "context" |
| "errors" |
| "log" |
| "net/http" |
| "os" |
| "os/signal" |
| "strings" |
| "sync/atomic" |
| "syscall" |
| "time" |
|
|
| "ccLoad/internal/app" |
| "ccLoad/internal/storage" |
| "ccLoad/internal/util" |
| "ccLoad/internal/version" |
|
|
| "github.com/gin-gonic/gin" |
| "github.com/joho/godotenv" |
| ) |
|
|
| |
| var restartRequested atomic.Bool |
|
|
| |
| func RequestRestart() { |
| restartRequested.Store(true) |
| } |
|
|
| |
| func execSelf() { |
| executable, err := os.Executable() |
| if err != nil { |
| log.Printf("[ERROR] 获取可执行文件路径失败: %v", err) |
| return |
| } |
|
|
| log.Printf("[INFO] 正在重启程序: %s", executable) |
|
|
| |
| |
| if err := syscall.Exec(executable, os.Args, os.Environ()); err != nil { |
| log.Printf("[ERROR] 重启失败: %v", err) |
| } |
| } |
|
|
| |
| var defaultTrustedProxies = []string{ |
| "10.0.0.0/8", |
| "172.16.0.0/12", |
| "192.168.0.0/16", |
| "100.64.0.0/10", |
| "127.0.0.0/8", |
| "::1/128", |
| } |
|
|
| |
| |
| |
| func getTrustedProxies() []string { |
| v := os.Getenv("TRUSTED_PROXIES") |
| if v == "" { |
| return defaultTrustedProxies |
| } |
| if v == "none" { |
| return nil |
| } |
| var proxies []string |
| for p := range strings.SplitSeq(v, ",") { |
| if p = strings.TrimSpace(p); p != "" { |
| proxies = append(proxies, p) |
| } |
| } |
| if len(proxies) == 0 { |
| return nil |
| } |
| return proxies |
| } |
|
|
| func main() { |
| |
| version.PrintBanner() |
|
|
| |
| version.StartChecker() |
|
|
| |
| if err := godotenv.Load(); err != nil { |
| log.Printf("未找到 .env 文件: %v", err) |
| } |
|
|
| |
| if os.Getenv("GIN_MODE") == "" { |
| gin.SetMode(gin.ReleaseMode) |
| } |
|
|
| |
| app.SetEmbedFS(WebFS, "web") |
|
|
| |
| store, err := storage.NewStore() |
| if err != nil { |
| log.Fatalf("存储初始化失败: %v", err) |
| } |
|
|
| |
|
|
| srv := app.NewServer(store) |
|
|
| |
| |
| app.RestartFunc = func() { |
| RequestRestart() |
|
|
| p, err := os.FindProcess(os.Getpid()) |
| if err != nil { |
| log.Printf("[ERROR] 查找进程失败: %v", err) |
| return |
| } |
| if err := p.Signal(syscall.SIGTERM); err != nil { |
| log.Printf("[ERROR] 发送 SIGTERM 失败: %v", err) |
| } |
| } |
|
|
| |
| r := gin.New() |
|
|
| |
| |
| |
| |
| trustedProxies := getTrustedProxies() |
| if trustedProxies == nil { |
| if err := r.SetTrustedProxies(nil); err != nil { |
| log.Fatalf("[FATAL] 设置可信代理失败: %v", err) |
| } |
| log.Printf("[CONFIG] 可信代理: 无 (直接暴露)") |
| } else { |
| if err := r.SetTrustedProxies(trustedProxies); err != nil { |
| log.Fatalf("[FATAL] 设置可信代理失败: %v (配置: %v)", err, trustedProxies) |
| } |
| log.Printf("[CONFIG] 可信代理: %v", trustedProxies) |
| } |
|
|
| |
| |
| if util.ParseBoolDefault(os.Getenv("GIN_LOG"), true) { |
| r.Use(gin.Logger()) |
| } |
| r.Use(gin.Recovery()) |
|
|
| |
| srv.SetupRoutes(r) |
|
|
| |
|
|
| addr := ":8080" |
| if v := os.Getenv("PORT"); v != "" { |
| if !strings.HasPrefix(v, ":") { |
| v = ":" + v |
| } |
| addr = v |
| } |
|
|
| |
| |
| writeTimeout := srv.GetWriteTimeout() |
| httpServer := &http.Server{ |
| Addr: addr, |
| Handler: r, |
|
|
| |
| |
| ReadHeaderTimeout: 5 * time.Second, |
| ReadTimeout: 120 * time.Second, |
| WriteTimeout: writeTimeout, |
| IdleTimeout: 60 * time.Second, |
| } |
| log.Printf("[CONFIG] HTTP WriteTimeout: %v", writeTimeout) |
|
|
| |
| go func() { |
| log.Printf("[INFO] HTTP 监听地址: %s", addr) |
| if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { |
| log.Fatalf("HTTP服务器启动失败: %v", err) |
| } |
| }() |
|
|
| |
| quit := make(chan os.Signal, 1) |
| signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) |
| <-quit |
|
|
| |
| signal.Stop(quit) |
| close(quit) |
|
|
| log.Println("收到关闭信号,正在优雅关闭服务器...") |
|
|
| |
| shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| defer cancel() |
|
|
| |
| if err := httpServer.Shutdown(shutdownCtx); err != nil { |
| log.Printf("HTTP服务器关闭超时: %v,强制关闭连接", err) |
| |
| _ = httpServer.Close() |
| } |
|
|
| |
| taskShutdownCtx, taskCancel := context.WithTimeout(context.Background(), 10*time.Second) |
| defer taskCancel() |
|
|
| if err := srv.Shutdown(taskShutdownCtx); err != nil { |
| log.Printf("Server后台任务关闭错误: %v", err) |
| } |
|
|
| log.Println("✅ 服务器已优雅关闭") |
|
|
| |
| if restartRequested.Load() { |
| log.Println("🔄 检测到重启请求,正在重启...") |
| execSelf() |
| |
| log.Println("[ERROR] 重启失败,程序退出") |
| } |
| } |
|
|