package main import ( "context" "flag" "net/http" "os" "os/signal" "syscall" "time" "spore-gateway/internal/discovery" "spore-gateway/internal/mqtt" "spore-gateway/internal/server" "spore-gateway/pkg/config" log "github.com/sirupsen/logrus" ) func main() { // Parse command line flags configFile := flag.String("config", "", "Path to configuration file") port := flag.String("port", "3001", "HTTP server port") udpPort := flag.String("udp-port", "4210", "UDP discovery port") mqttServer := flag.String("mqtt", "", "Enable MQTT integration with server URL (e.g., tcp://localhost:1883)") logLevel := flag.String("log-level", "info", "Log level (debug, info, warn, error)") flag.Parse() // Initialize logger level, err := log.ParseLevel(*logLevel) if err != nil { log.WithError(err).Fatal("Invalid log level") } log.SetLevel(level) log.SetFormatter(&log.TextFormatter{ FullTimestamp: true, }) log.Info("Starting SPORE Gateway") // Load configuration cfg := config.Load(*configFile) if cfg == nil { log.Fatal("Failed to load configuration") } // Override config with command line arguments if *port != "3001" { cfg.HTTPPort = *port } if *udpPort != "4210" { cfg.UDPPort = *udpPort } log.WithFields(log.Fields{ "http_port": cfg.HTTPPort, "udp_port": cfg.UDPPort, }).Info("Configuration loaded") // Initialize node discovery nodeDiscovery := discovery.NewNodeDiscovery(cfg.UDPPort) // Initialize HTTP server httpServer := server.NewHTTPServer(cfg.HTTPPort, nodeDiscovery) // Initialize MQTT client if enabled var mqttClient *mqtt.MQTTClient // Check for MQTT server from flag or environment variable mqttServerURL := *mqttServer if mqttServerURL == "" { mqttServerURL = os.Getenv("MQTT_SERVER") } if mqttServerURL != "" { log.WithField("server", mqttServerURL).Info("Initializing MQTT client") mqttClient = mqtt.NewMQTTClientFromEnv(mqttServerURL) // Set callback to forward MQTT messages to WebSocket mqttClient.SetMessageCallback(func(topic string, data []byte) { httpServer.BroadcastMQTTMessage(topic, data) }) if err := mqttClient.Connect(); err != nil { log.WithError(err).Fatal("Failed to connect to MQTT broker") } } // Setup graceful shutdown ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() // Start UDP discovery server go func() { if err := nodeDiscovery.Start(); err != nil { log.WithError(err).Fatal("Failed to start node discovery") } }() // Start HTTP server go func() { log.WithField("port", cfg.HTTPPort).Info("Starting HTTP server") if err := httpServer.Start(); err != nil && err != http.ErrServerClosed { log.WithError(err).Fatal("Failed to start HTTP server") } }() // Wait for interrupt signal <-ctx.Done() stop() log.Info("Shutting down servers...") // Create shutdown context with timeout shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // Shutdown MQTT client if mqttClient != nil { if err := mqttClient.Shutdown(shutdownCtx); err != nil { log.WithError(err).Error("MQTT client shutdown error") } } // Shutdown HTTP server if err := httpServer.Shutdown(shutdownCtx); err != nil { log.WithError(err).Error("HTTP server shutdown error") } // Shutdown node discovery if err := nodeDiscovery.Shutdown(shutdownCtx); err != nil { log.WithError(err).Error("Node discovery shutdown error") } log.Info("Shutdown complete") }