128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
|
|
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")
|
||
|
|
}
|