package server import ( "log" "os" "github.com/gin-gonic/gin" "github.com/joho/godotenv" "sensor-server/internal/api" "sensor-server/internal/cache" "sensor-server/internal/database" "sensor-server/internal/websocket" ) // Server 서버 구조체 type Server struct { router *gin.Engine hub *websocket.Hub } // NewServer 새로운 서버 인스턴스 생성 func NewServer() *Server { // 환경변수 로드 if err := godotenv.Load(); err != nil { log.Println("No .env file found, using environment variables") } // Gin 모드 설정 if os.Getenv("GIN_MODE") == "release" { gin.SetMode(gin.ReleaseMode) } router := gin.New() // gin.Default() 대신 gin.New() 사용 hub := websocket.NewHub() // 로깅 미들웨어 추가 router.Use(gin.Logger()) router.Use(gin.Recovery()) // CORS 미들웨어 추가 router.Use(func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() }) return &Server{ router: router, hub: hub, } } // Initialize 서버 초기화 func (s *Server) Initialize() error { // 데이터베이스 초기화 if err := database.InitDatabase(); err != nil { return err } // Redis 초기화 if err := cache.InitRedis(); err != nil { return err } // 라우터 설정 s.setupRoutes() // WebSocket 허브 시작 go s.hub.Run() return nil } // setupRoutes 라우터 설정 func (s *Server) setupRoutes() { handler := api.NewHandler(s.hub) // WebSocket 엔드포인트 (가장 먼저 등록) s.router.GET("/ws", func(c *gin.Context) { log.Printf("WebSocket 요청 수신: %s", c.Request.URL.Path) websocket.ServeWs(s.hub, c.Writer, c.Request) }) // API 그룹 api := s.router.Group("/api") { // 헬스체크 api.GET("/health", handler.HealthCheck) // 센서 데이터 수신 api.POST("/sensor-data", handler.ReceiveSensorData) // 확장된 센서 데이터 수신 api.POST("/sensor/extended-data", handler.ReceiveExtendedSensorData) // 디바이스 관련 api.GET("/devices", handler.GetDevices) api.GET("/devices/:deviceId/latest", handler.GetLatestData) api.GET("/devices/:deviceId/history", handler.GetHistory) } // 정적 파일 서빙 (개발용) s.router.Static("/static", "./static") } // Run 서버 실행 func (s *Server) Run() error { port := os.Getenv("PORT") if port == "" { port = "8080" } log.Printf("Server starting on port %s", port) return s.router.Run(":" + port) } // GetRouter 라우터 반환 (테스트용) func (s *Server) GetRouter() *gin.Engine { return s.router }