Files

128 lines
3.2 KiB
Go
Raw Permalink Normal View History

2026-09-15 01:38:15 +09:00
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")
}