package main import ( "context" "net/http" "os" "os/signal" "syscall" "time" "ezops/internal/api/routes" "ezops/internal/config" "ezops/pkg/database" "ezops/pkg/logger" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // 版本信息(通过编译时 ldflags 注入) var ( Version = "dev" BuildTime = "unknown" GitCommit = "unknown" ) // @title AIOps运维平台 API // @version 1.0 // @description AIOps智能运维平台后端API文档 // @termsOfService http://swagger.io/terms/ // @contact.name API Support // @contact.url http://www.swagger.io/support // @contact.email support@swagger.io // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @host localhost:8080 // @BasePath /api/v1 // @securityDefinitions.apikey Bearer // @in header // @name Authorization // @description Type "Bearer" followed by a space and JWT token. func main() { // 加载配置 cfg := config.Load() // 初始化日志 log := logger.New(cfg.LogLevel) defer log.Sync() // 设置Gin模式 if cfg.Mode == "production" { gin.SetMode(gin.ReleaseMode) } // 初始化数据库 db, err := database.New(cfg.Database) if err != nil { log.Fatal("failed to connect database", zap.Error(err)) } // 自动迁移 if err := database.AutoMigrate(db); err != nil { log.Fatal("failed to migrate database", zap.Error(err)) } // 创建Gin实例 r := gin.New() // 中间件 r.Use(gin.Recovery()) r.Use(logger.GinLogger(log)) r.Use(CORS()) // 版本信息 API r.GET("/version", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "version": Version, "build_time": BuildTime, "git_commit": GitCommit, }) }) // 注册路由 routes.Register(r, db, log, cfg) // 创建HTTP服务器 srv := &http.Server{ Addr: ":" + cfg.Port, Handler: r, } // 优雅关闭 go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal("failed to start server", zap.Error(err)) } }() log.Info("server started", zap.String("port", cfg.Port)) // 等待中断信号 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Info("shutting down server...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("server forced to shutdown", zap.Error(err)) } log.Info("server exited") } // CORS 跨域中间件 func CORS() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS") c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length") c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } }