Spaces:
Paused
Paused
Update main.go
Browse files
main.go
CHANGED
|
@@ -12,92 +12,82 @@ import (
|
|
| 12 |
|
| 13 |
"github.com/gin-contrib/cors"
|
| 14 |
"github.com/gin-gonic/gin"
|
| 15 |
-
"github.com/joho/godotenv"
|
| 16 |
)
|
| 17 |
|
| 18 |
func main() {
|
| 19 |
-
// Load .env file if present (optional, good for local dev)
|
| 20 |
_ = godotenv.Load()
|
| 21 |
|
| 22 |
-
// Load configuration
|
| 23 |
cfg := LoadConfig()
|
| 24 |
|
| 25 |
-
// Set Gin mode (release or debug)
|
| 26 |
if cfg.GinMode == "release" {
|
| 27 |
gin.SetMode(gin.ReleaseMode)
|
| 28 |
} else {
|
| 29 |
gin.SetMode(gin.DebugMode)
|
| 30 |
}
|
|
|
|
| 31 |
log.Printf("Starting Go Proxy Server in %s mode...", gin.Mode())
|
| 32 |
|
| 33 |
-
// Initialize Gin router
|
| 34 |
router := gin.New()
|
| 35 |
|
| 36 |
-
//
|
| 37 |
-
|
| 38 |
-
router.Use(gin.
|
| 39 |
-
|
| 40 |
router.Use(cors.New(cors.Config{
|
| 41 |
AllowOrigins: []string{"*"},
|
| 42 |
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
|
| 43 |
-
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-API-Key"},
|
| 44 |
ExposeHeaders: []string{"Content-Length"},
|
| 45 |
AllowCredentials: true,
|
| 46 |
MaxAge: 12 * time.Hour,
|
| 47 |
}))
|
| 48 |
|
| 49 |
-
// --- Routes ---
|
| 50 |
-
// Health check
|
| 51 |
router.GET("/health", HealthCheckHandler)
|
| 52 |
|
| 53 |
-
// Main proxy endpoint group
|
| 54 |
v1 := router.Group("/v1")
|
| 55 |
{
|
| 56 |
-
// Apply API Key Authentication middleware if keys are configured
|
| 57 |
if len(cfg.ValidAPIKeys) > 0 {
|
|
|
|
| 58 |
log.Printf("API Key authentication enabled (%d keys configured).", len(cfg.ValidAPIKeys))
|
| 59 |
v1.Use(APIKeyAuthMiddleware(cfg.ValidAPIKeys))
|
| 60 |
} else {
|
|
|
|
| 61 |
log.Println("WARN: No PROXY_API_KEYS configured. Proxy is open (no authentication).")
|
| 62 |
}
|
| 63 |
v1.POST("/messages", MessagesHandler)
|
| 64 |
}
|
| 65 |
|
| 66 |
-
// --- Server Setup ---
|
| 67 |
server := &http.Server{
|
| 68 |
Addr: fmt.Sprintf(":%s", cfg.Port),
|
| 69 |
Handler: router,
|
| 70 |
-
// Add timeouts for production hardening
|
| 71 |
ReadTimeout: 10 * time.Second,
|
| 72 |
-
WriteTimeout: cfg.ReadTimeout + 30*time.Second,
|
| 73 |
IdleTimeout: 120 * time.Second,
|
| 74 |
}
|
| 75 |
|
| 76 |
-
// --- Graceful Shutdown ---
|
| 77 |
-
// Run server in a goroutine so it doesn't block
|
| 78 |
go func() {
|
|
|
|
| 79 |
log.Printf("Server listening on port %s", cfg.Port)
|
| 80 |
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
|
|
| 81 |
log.Fatalf("listen: %s\n", err)
|
| 82 |
}
|
| 83 |
}()
|
| 84 |
|
| 85 |
-
// Wait for interrupt signal to gracefully shut down the server
|
| 86 |
quit := make(chan os.Signal, 1)
|
| 87 |
-
// kill (no param) default send syscall.SIGTERM
|
| 88 |
-
// kill -2 is syscall.SIGINT
|
| 89 |
-
// kill -9 is syscall.SIGKILL but can't be caught, so don't need to add it
|
| 90 |
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
| 91 |
<-quit
|
|
|
|
| 92 |
log.Println("Shutting down server...")
|
| 93 |
|
| 94 |
-
// The context is used to inform the server it has 5 seconds to finish
|
| 95 |
-
// the requests it is currently handling
|
| 96 |
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
| 97 |
defer cancel()
|
| 98 |
if err := server.Shutdown(ctx); err != nil {
|
|
|
|
| 99 |
log.Fatal("Server forced to shutdown:", err)
|
| 100 |
}
|
| 101 |
|
|
|
|
| 102 |
log.Println("Server exiting")
|
| 103 |
-
}
|
|
|
|
| 12 |
|
| 13 |
"github.com/gin-contrib/cors"
|
| 14 |
"github.com/gin-gonic/gin"
|
| 15 |
+
"github.com/joho/godotenv"
|
| 16 |
)
|
| 17 |
|
| 18 |
func main() {
|
|
|
|
| 19 |
_ = godotenv.Load()
|
| 20 |
|
|
|
|
| 21 |
cfg := LoadConfig()
|
| 22 |
|
|
|
|
| 23 |
if cfg.GinMode == "release" {
|
| 24 |
gin.SetMode(gin.ReleaseMode)
|
| 25 |
} else {
|
| 26 |
gin.SetMode(gin.DebugMode)
|
| 27 |
}
|
| 28 |
+
// Giữ lại: Log khởi động quan trọng
|
| 29 |
log.Printf("Starting Go Proxy Server in %s mode...", gin.Mode())
|
| 30 |
|
|
|
|
| 31 |
router := gin.New()
|
| 32 |
|
| 33 |
+
// Giữ lại: Gin Logger là tiêu chuẩn, nhưng có thể xem xét loại bỏ nếu muốn log *cực kỳ* ít.
|
| 34 |
+
// Hiện tại giữ lại để có thông tin request cơ bản.
|
| 35 |
+
router.Use(gin.Logger())
|
| 36 |
+
router.Use(gin.Recovery())
|
| 37 |
router.Use(cors.New(cors.Config{
|
| 38 |
AllowOrigins: []string{"*"},
|
| 39 |
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
|
| 40 |
+
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-API-Key"},
|
| 41 |
ExposeHeaders: []string{"Content-Length"},
|
| 42 |
AllowCredentials: true,
|
| 43 |
MaxAge: 12 * time.Hour,
|
| 44 |
}))
|
| 45 |
|
|
|
|
|
|
|
| 46 |
router.GET("/health", HealthCheckHandler)
|
| 47 |
|
|
|
|
| 48 |
v1 := router.Group("/v1")
|
| 49 |
{
|
|
|
|
| 50 |
if len(cfg.ValidAPIKeys) > 0 {
|
| 51 |
+
// Giữ lại: Log khởi động quan trọng
|
| 52 |
log.Printf("API Key authentication enabled (%d keys configured).", len(cfg.ValidAPIKeys))
|
| 53 |
v1.Use(APIKeyAuthMiddleware(cfg.ValidAPIKeys))
|
| 54 |
} else {
|
| 55 |
+
// Giữ lại: Log cảnh báo quan trọng (cũng có trong config.go, nhưng ở đây cũng tốt)
|
| 56 |
log.Println("WARN: No PROXY_API_KEYS configured. Proxy is open (no authentication).")
|
| 57 |
}
|
| 58 |
v1.POST("/messages", MessagesHandler)
|
| 59 |
}
|
| 60 |
|
|
|
|
| 61 |
server := &http.Server{
|
| 62 |
Addr: fmt.Sprintf(":%s", cfg.Port),
|
| 63 |
Handler: router,
|
|
|
|
| 64 |
ReadTimeout: 10 * time.Second,
|
| 65 |
+
WriteTimeout: cfg.ReadTimeout + 30*time.Second,
|
| 66 |
IdleTimeout: 120 * time.Second,
|
| 67 |
}
|
| 68 |
|
|
|
|
|
|
|
| 69 |
go func() {
|
| 70 |
+
// Giữ lại: Log khởi động quan trọng
|
| 71 |
log.Printf("Server listening on port %s", cfg.Port)
|
| 72 |
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
| 73 |
+
// Giữ lại: Log lỗi nghiêm trọng
|
| 74 |
log.Fatalf("listen: %s\n", err)
|
| 75 |
}
|
| 76 |
}()
|
| 77 |
|
|
|
|
| 78 |
quit := make(chan os.Signal, 1)
|
|
|
|
|
|
|
|
|
|
| 79 |
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
| 80 |
<-quit
|
| 81 |
+
// Giữ lại: Log tắt server
|
| 82 |
log.Println("Shutting down server...")
|
| 83 |
|
|
|
|
|
|
|
| 84 |
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
| 85 |
defer cancel()
|
| 86 |
if err := server.Shutdown(ctx); err != nil {
|
| 87 |
+
// Giữ lại: Log lỗi nghiêm trọng
|
| 88 |
log.Fatal("Server forced to shutdown:", err)
|
| 89 |
}
|
| 90 |
|
| 91 |
+
// Giữ lại: Log tắt server
|
| 92 |
log.Println("Server exiting")
|
| 93 |
+
}
|