| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- package main
- import (
- "fmt"
- "io"
- "log"
- "net/http"
- "os"
- "time"
- "github.com/gin-gonic/gin"
- "github.com/golang-migrate/migrate/v4"
- _ "github.com/golang-migrate/migrate/v4/database/postgres"
- _ "github.com/golang-migrate/migrate/v4/source/file"
- "ems-backend/db"
- "ems-backend/models"
- "ems-backend/routes"
- "ems-backend/services"
- "ems-backend/utils"
- )
- func initSchema() {
- // Construct DB URL from env vars or use a default one suitable for the container environment
- // Expected format: postgres://user:password@host:port/dbname?sslmode=disable
- dbUser := os.Getenv("POSTGRES_USER")
- if dbUser == "" { dbUser = "ems" }
- dbPass := os.Getenv("DB_PASSWORD") // Note: inconsistent naming in env, checking plan
- if dbPass == "" { dbPass = "ems_pass" } // Fallback
- dbHost := os.Getenv("POSTGRES_HOST")
- if dbHost == "" { dbHost = "postgres" }
- dbPort := os.Getenv("POSTGRES_PORT")
- if dbPort == "" { dbPort = "5432" }
- dbName := os.Getenv("POSTGRES_DB")
- if dbName == "" { dbName = "ems" }
- // If DB_PASSWORD env var is not set but POSTGRES_PASSWORD is (from docker-compose)
- if dbPass == "ems_pass" && os.Getenv("POSTGRES_PASSWORD") != "" {
- dbPass = os.Getenv("POSTGRES_PASSWORD")
- }
- dbUrl := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
- dbUser, dbPass, dbHost, dbPort, dbName)
- log.Printf("Initializing schema migration...")
- // Point to the migration files inside the container
- var m *migrate.Migrate
- var err error
- maxRetries := 30
- for i := 0; i < maxRetries; i++ {
- m, err = migrate.New("file:///app/migrations", dbUrl)
- if err == nil {
- break
- }
- log.Printf("Migration initialization failed (attempt %d/%d): %v. Retrying in 2 seconds...", i+1, maxRetries, err)
- time.Sleep(2 * time.Second)
- }
- if err != nil {
- log.Printf("Migration initialization finally failed (might be in dev or path missing): %v", err)
- return
- }
- if err := m.Up(); err != nil && err != migrate.ErrNoChange {
- log.Fatal("Database migration failed:", err)
- }
- log.Println("Database schema is up to date.")
- }
- func main() {
- initSchema()
- models.InitDB()
-
- // --- Initialize Log Rotation ---
- logWriter := utils.NewDailyLogWriter("logs")
- // Output to both stdout and file
- multiWriter := io.MultiWriter(os.Stdout, logWriter)
-
- // Configure standard logger
- log.SetOutput(multiWriter)
- log.SetFlags(log.LstdFlags | log.Lshortfile)
-
- // Configure Gin logger
- gin.DefaultWriter = multiWriter
-
- // Initialize Time Series Database (TDengine)
- db.InitTDengine()
- // Start async TDengine writer when TDengine is configured (decouples collection from write)
- if db.TD != nil {
- services.GlobalTDengineWriter = services.NewTDengineWriter()
- services.GlobalTDengineWriter.Start()
- defer services.GlobalTDengineWriter.Stop()
- }
-
- // Initialize Backup Service
- services.InitBackupService()
- // Initialize Alarm Service
- services.NewAlarmService()
- // Start Data Collector Service
- collector := services.NewCollectorService()
- collector.Start()
- // Note: collector.Stop() is not strictly needed as container kill handles cleanup,
- // but can be added if we implement graceful shutdown.
- r := gin.Default()
- // Setup Routes
- routes.SetupRoutes(r)
- // Health Check
- r.GET("/ping", func(c *gin.Context) {
- c.JSON(http.StatusOK, gin.H{
- "message": "pong",
- "system": "EMS Backend",
- })
- })
- // API Group
- v1 := r.Group("/api/v1")
- {
- v1.GET("/info", func(c *gin.Context) {
- c.JSON(http.StatusOK, gin.H{
- "version": "1.0.0",
- "env": os.Getenv("GIN_MODE"),
- })
- })
- }
- port := os.Getenv("PORT")
- if port == "" {
- port = "8080"
- }
- fmt.Printf("Server starting on port %s...\n", port)
- r.Run(":" + port)
- }
|