package main import ( "context" "flag" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/user/go-proxy/internal/config" "github.com/user/go-proxy/internal/proxy" "github.com/user/go-proxy/internal/router" "github.com/user/go-proxy/pkg/middleware" ) func main() { // Parse command line flags configPath := flag.String("config", "config.yaml", "Path to configuration file") flag.Parse() // 1. Load configuration dynamically cfg, err := config.LoadConfig(*configPath) if err != nil { log.Fatalf("Error loading config: %v", err) os.Exit(1) } fmt.Printf("Loaded configuration from %s\n", *configPath) // 2. Setup Router r := router.NewRouter(cfg.HTTP) // 3. Setup Middleware Chain handler := middleware.Chain( r, middleware.Recovery(), middleware.Logger(), middleware.RateLimit(10, 20), ) // 4. Setup Config Watcher (Hot-Reload) err = config.WatchConfig(*configPath, func(newCfg *config.Config) { log.Println("Applying new configuration...") r.UpdateConfig(newCfg.HTTP) }) if err != nil { log.Printf("Warning: Failed to start config watcher: %v", err) } // 5. Start TCP Proxy in a separate goroutine (if configured) if cfg.TCP.Port > 0 && cfg.TCP.Backend != "" { go func() { if err := proxy.RunTCPProxy(cfg.TCP.Port, cfg.TCP.Backend); err != nil { log.Printf("TCP proxy failed: %v", err) } }() } // 6. Start UDP Proxy in a separate goroutine (if configured) if cfg.UDP.Port > 0 && cfg.UDP.Backend != "" { go func() { if err := proxy.RunUDPProxy(cfg.UDP.Port, cfg.UDP.Backend); err != nil { log.Printf("UDP proxy failed: %v", err) } }() } // Prepare HTTP Servers httpServer := &http.Server{ Addr: fmt.Sprintf(":%d", cfg.HTTP.Port), Handler: handler, } var httpsServer *http.Server if cfg.HTTP.TLS.Enabled { httpsServer = &http.Server{ Addr: fmt.Sprintf(":%d", cfg.HTTP.TLS.Port), Handler: handler, } } // 6. Start HTTPS Server (if enabled) if httpsServer != nil { go func() { log.Printf("Starting HTTPS proxy server on port %s\n", httpsServer.Addr) if err := httpsServer.ListenAndServeTLS(cfg.HTTP.TLS.CertFile, cfg.HTTP.TLS.KeyFile); err != nil && err != http.ErrServerClosed { log.Fatalf("HTTPS Server error: %v", err) } }() } // 7. Start HTTP Server go func() { log.Printf("Starting HTTP proxy server on port %s\n", httpServer.Addr) if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("HTTP Server error: %v", err) } }() // 8. Graceful Shutdown Waiter quit := make(chan os.Signal, 1) // kill (no param) default send syscall.SIGTERM // kill -2 is syscall.SIGINT // kill -9 is syscall.SIGKILL but can't be caught, so don't need to add it signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutdown signal received, draining traffic...") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if httpsServer != nil { if err := httpsServer.Shutdown(ctx); err != nil { log.Printf("HTTPS Server forced to shutdown: %v", err) } } if err := httpServer.Shutdown(ctx); err != nil { log.Printf("HTTP Server forced to shutdown: %v", err) } log.Println("Proxy server exiting gracefully") }