package main import ( "basic-sensor-receiver/app" "basic-sensor-receiver/middleware" "basic-sensor-receiver/routes" "context" "fmt" "log" "net/http" "os/signal" "syscall" "github.com/gin-gonic/gin" "github.com/joho/godotenv" _ "github.com/mattn/go-sqlite3" ) func main() { err := godotenv.Load() if err != nil { log.Println("Error loading .env file: ", err) } server := app.InitializeServer() gin.SetMode(server.Config.Mode) router := gin.Default() // Front-end resources router.StaticFile("/", "client/index.html") router.Static("/assets", "client/assets") // Only allow CORS in development mode if server.Config.Mode == "debug" { router.Use(middleware.CorsMiddleware()) } if server.Config.AuthEnabled { // User login route router.POST("/api/login", routes.Login(server)) } // Routes that are only accessible after logging in loginProtected := router.Group("/", middleware.LoginAuthMiddleware(server)) loginProtected.GET("/api/sensors", routes.GetSensors(server)) loginProtected.POST("/api/sensors", routes.PostSensors(server)) loginProtected.GET("/api/sensors/:sensor", routes.GetSensor(server)) loginProtected.PUT("/api/sensors/:sensor", routes.PutSensor(server)) loginProtected.DELETE("/api/sensors/:sensor", routes.DeleteSensor(server)) loginProtected.GET("/api/sensors/:sensor/values/latest", routes.GetSensorLatestValue(server)) loginProtected.GET("/api/sensors/:sensor/values", routes.GetSensorValues(server)) //loginProtected.GET("/api/sensors/:sensor/config", routes.GetSensorConfig(server)) //loginProtected.PUT("/api/sensors/:sensor/config/:key", routes.PutSensorConfig(server)) loginProtected.GET("/api/dashboards", routes.GetDashboards(server)) loginProtected.POST("/api/dashboards", routes.PostDashboard(server)) loginProtected.GET("/api/dashboards/:id", routes.GetDashboardById(server)) loginProtected.PUT("/api/dashboards/:id", routes.PutDashboard(server)) loginProtected.DELETE("/api/dashboards/:id", routes.DeleteDashboard(server)) loginProtected.GET("/api/alerts", routes.GetAlerts(server)) loginProtected.POST("/api/alerts", routes.PostAlerts(server)) loginProtected.GET("/api/alerts/:alertId", routes.GetAlert(server)) loginProtected.PUT("/api/alerts/:alertId", routes.PutAlert(server)) loginProtected.DELETE("/api/alerts/:alertId", routes.DeleteAlert(server)) loginProtected.GET("/api/contact-points", routes.GetContactPoints(server)) loginProtected.POST("/api/contact-points", routes.PostContactPoints(server)) loginProtected.GET("/api/contact-points/:contactPointId", routes.GetContactPoint(server)) loginProtected.PUT("/api/contact-points/:contactPointId", routes.PutContactPoint(server)) loginProtected.DELETE("/api/contact-points/:contactPointId", routes.DeleteContactPoint(server)) loginProtected.POST("/api/contact-points/test", routes.TestContactPoint(server)) loginProtected.GET("/api/mqtt/brokers", routes.GetMQTTBrokers(server)) loginProtected.POST("/api/mqtt/brokers", routes.PostMQTTBroker(server)) loginProtected.GET("/api/mqtt/brokers/:brokerId", routes.GetMQTTBroker(server)) loginProtected.PUT("/api/mqtt/brokers/:brokerId", routes.PutMQTTBroker(server)) loginProtected.DELETE("/api/mqtt/brokers/:brokerId", routes.DeleteMQTTBroker(server)) loginProtected.POST("/api/mqtt/brokers/:brokerId/publish", routes.PostMQTTBrokerPublish(server)) if server.Config.AuthEnabled { loginProtected.POST("/api/logout", routes.Logout(server)) } // Routes accessible using auth key keyProtected := router.Group("/", middleware.KeyAuthMiddleware(server)) keyProtected.POST("/api/sensors/:sensor/values", routes.PostSensorValues(server)) // Starts session cleanup goroutine server.StartCleaner() // Starts alerts handling goroutine server.StartAlerts() // Graceful shutdown using SIGTERM or SIGINT ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() // Prepare http server address := fmt.Sprintf("%s:%d", server.Config.Ip, server.Config.Port) srv := &http.Server{ Addr: address, Handler: router, } // Run the server in a goroutine so that it doesn't block and we can stop it later go func() { log.Println("Running server on", address) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("Listen: %s\n", err) } }() // Wait for shutdown signal <-ctx.Done() // Shutdown the server log.Println("Shutting down server...") if err := srv.Shutdown(context.TODO()); err != nil { log.Fatalf("Server shutdown failed: %v", err) } if err := server.DB.Close(); err != nil { log.Fatalf("Database close failed: %v", err) } log.Println("Server stopped") }