// Package main is the main package for the WeKnora server // It contains the main function and the entry point for the server // // @title WeKnora API // @version 1.0 // @description WeKnora 知识库管理系统 API 文档 // @termsOfService http://swagger.io/terms/ // // @contact.name WeKnora Github // @contact.url https://github.com/Tencent/WeKnora // // @BasePath /api/v1 // // @securityDefinitions.apikey Bearer // @in header // @name Authorization // @description 用户登录认证:输入 Bearer {token} 格式的 JWT 令牌 // @securityDefinitions.apikey ApiKeyAuth // @in header // @name X-API-Key // @description 租户身份认证:输入 sk- 开头的 API Key package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" "github.com/Tencent/WeKnora/internal/config" "github.com/Tencent/WeKnora/internal/container" "github.com/Tencent/WeKnora/internal/logger" "github.com/Tencent/WeKnora/internal/runtime" "github.com/Tencent/WeKnora/internal/tracing" "github.com/Tencent/WeKnora/internal/types/interfaces" ) func main() { // Set Gin mode if os.Getenv("GIN_MODE") == "release" { gin.SetMode(gin.ReleaseMode) } else { gin.SetMode(gin.DebugMode) } // Build dependency injection container c := container.BuildContainer(runtime.GetContainer()) // Run application err := c.Invoke(func( cfg *config.Config, router *gin.Engine, tracer *tracing.Tracer, resourceCleaner interfaces.ResourceCleaner, ) error { // Create HTTP server server := &http.Server{ Addr: fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port), Handler: router, } ctx, done := context.WithCancel(context.Background()) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) go func() { sig := <-signals logger.Infof(context.Background(), "Received signal: %v, starting server shutdown...", sig) // Create a context with timeout for server shutdown shutdownTimeout := cfg.Server.ShutdownTimeout if shutdownTimeout == 0 { shutdownTimeout = 30 * time.Second } shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), shutdownTimeout) defer shutdownCancel() if err := server.Shutdown(shutdownCtx); err != nil { logger.Fatalf(context.Background(), "Server forced to shutdown: %v", err) } // Clean up all registered resources logger.Info(context.Background(), "Cleaning up resources...") errs := resourceCleaner.Cleanup(shutdownCtx) if len(errs) > 0 { logger.Errorf(context.Background(), "Errors occurred during resource cleanup: %v", errs) } logger.Info(context.Background(), "Server has exited") done() }() // Start server logger.Infof(context.Background(), "Server is running at %s:%d", cfg.Server.Host, cfg.Server.Port) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { return fmt.Errorf("failed to start server: %v", err) } // Wait for shutdown signal <-ctx.Done() return nil }) if err != nil { logger.Fatalf(context.Background(), "Failed to run application: %v", err) } }