main.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "net/http"
  7. "os"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/golang-migrate/migrate/v4"
  11. _ "github.com/golang-migrate/migrate/v4/database/postgres"
  12. _ "github.com/golang-migrate/migrate/v4/source/file"
  13. "ems-backend/db"
  14. "ems-backend/models"
  15. "ems-backend/routes"
  16. "ems-backend/services"
  17. "ems-backend/utils"
  18. )
  19. func initSchema() {
  20. // Construct DB URL from env vars or use a default one suitable for the container environment
  21. // Expected format: postgres://user:password@host:port/dbname?sslmode=disable
  22. dbUser := os.Getenv("POSTGRES_USER")
  23. if dbUser == "" { dbUser = "ems" }
  24. dbPass := os.Getenv("DB_PASSWORD") // Note: inconsistent naming in env, checking plan
  25. if dbPass == "" { dbPass = "ems_pass" } // Fallback
  26. dbHost := os.Getenv("POSTGRES_HOST")
  27. if dbHost == "" { dbHost = "postgres" }
  28. dbPort := os.Getenv("POSTGRES_PORT")
  29. if dbPort == "" { dbPort = "5432" }
  30. dbName := os.Getenv("POSTGRES_DB")
  31. if dbName == "" { dbName = "ems" }
  32. // If DB_PASSWORD env var is not set but POSTGRES_PASSWORD is (from docker-compose)
  33. if dbPass == "ems_pass" && os.Getenv("POSTGRES_PASSWORD") != "" {
  34. dbPass = os.Getenv("POSTGRES_PASSWORD")
  35. }
  36. dbUrl := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
  37. dbUser, dbPass, dbHost, dbPort, dbName)
  38. log.Printf("Initializing schema migration...")
  39. // Point to the migration files inside the container
  40. var m *migrate.Migrate
  41. var err error
  42. maxRetries := 30
  43. for i := 0; i < maxRetries; i++ {
  44. m, err = migrate.New("file:///app/migrations", dbUrl)
  45. if err == nil {
  46. break
  47. }
  48. log.Printf("Migration initialization failed (attempt %d/%d): %v. Retrying in 2 seconds...", i+1, maxRetries, err)
  49. time.Sleep(2 * time.Second)
  50. }
  51. if err != nil {
  52. log.Printf("Migration initialization finally failed (might be in dev or path missing): %v", err)
  53. return
  54. }
  55. if err := m.Up(); err != nil && err != migrate.ErrNoChange {
  56. log.Fatal("Database migration failed:", err)
  57. }
  58. log.Println("Database schema is up to date.")
  59. }
  60. func main() {
  61. initSchema()
  62. models.InitDB()
  63. // --- Initialize Log Rotation ---
  64. logWriter := utils.NewDailyLogWriter("logs")
  65. // Output to both stdout and file
  66. multiWriter := io.MultiWriter(os.Stdout, logWriter)
  67. // Configure standard logger
  68. log.SetOutput(multiWriter)
  69. log.SetFlags(log.LstdFlags | log.Lshortfile)
  70. // Configure Gin logger
  71. gin.DefaultWriter = multiWriter
  72. // Initialize Time Series Database (TDengine)
  73. db.InitTDengine()
  74. // Start async TDengine writer when TDengine is configured (decouples collection from write)
  75. if db.TD != nil {
  76. services.GlobalTDengineWriter = services.NewTDengineWriter()
  77. services.GlobalTDengineWriter.Start()
  78. defer services.GlobalTDengineWriter.Stop()
  79. }
  80. // Initialize Backup Service
  81. services.InitBackupService()
  82. // Initialize Alarm Service
  83. services.NewAlarmService()
  84. // Start Data Collector Service
  85. collector := services.NewCollectorService()
  86. collector.Start()
  87. // Note: collector.Stop() is not strictly needed as container kill handles cleanup,
  88. // but can be added if we implement graceful shutdown.
  89. r := gin.Default()
  90. // Setup Routes
  91. routes.SetupRoutes(r)
  92. // Health Check
  93. r.GET("/ping", func(c *gin.Context) {
  94. c.JSON(http.StatusOK, gin.H{
  95. "message": "pong",
  96. "system": "EMS Backend",
  97. })
  98. })
  99. // API Group
  100. v1 := r.Group("/api/v1")
  101. {
  102. v1.GET("/info", func(c *gin.Context) {
  103. c.JSON(http.StatusOK, gin.H{
  104. "version": "1.0.0",
  105. "env": os.Getenv("GIN_MODE"),
  106. })
  107. })
  108. }
  109. port := os.Getenv("PORT")
  110. if port == "" {
  111. port = "8080"
  112. }
  113. fmt.Printf("Server starting on port %s...\n", port)
  114. r.Run(":" + port)
  115. }