package handlers import ( "log" "net/http" "strconv" "sync" "github.com/gin-gonic/gin" "github.com/nemunaire/repeater/internal/config" "github.com/nemunaire/repeater/internal/hotspot" "github.com/nemunaire/repeater/internal/logging" "github.com/nemunaire/repeater/internal/models" "github.com/nemunaire/repeater/internal/station" "github.com/nemunaire/repeater/internal/wifi" ) // GetWiFiNetworks returns cached WiFi networks without scanning func GetWiFiNetworks(c *gin.Context) { networks, err := wifi.GetCachedNetworks() if err != nil { logging.AddLog("WiFi", "Erreur lors de la récupération des réseaux: "+err.Error()) c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur lors de la récupération des réseaux"}) return } c.JSON(http.StatusOK, networks) } // ScanWiFi handles WiFi network scanning func ScanWiFi(c *gin.Context) { networks, err := wifi.ScanNetworks() if err != nil { log.Printf("WiFi scan error: %v", err) logging.AddLog("WiFi", "Erreur lors du scan") c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur lors du scan WiFi"}) return } logging.AddLog("WiFi", "Scan terminé - "+strconv.Itoa(len(networks))+" réseaux trouvés") c.JSON(http.StatusOK, networks) } // ConnectWiFi handles WiFi connection requests func ConnectWiFi(c *gin.Context) { var req models.WiFiConnectRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Données invalides"}) return } logging.AddLog("WiFi", "Tentative de connexion") err := wifi.Connect(req.SSID, req.Password) if err != nil { // Backend errors may include credentials or low-level details // (dbus paths, kernel messages); keep them in the server log only. log.Printf("WiFi connect error: %v", err) logging.AddLog("WiFi", "Échec de connexion") c.JSON(http.StatusInternalServerError, gin.H{"error": "Échec de connexion"}) return } logging.AddLog("WiFi", "Connexion réussie") c.JSON(http.StatusOK, gin.H{"status": "success"}) } // DisconnectWiFi handles WiFi disconnection func DisconnectWiFi(c *gin.Context) { logging.AddLog("WiFi", "Tentative de déconnexion") err := wifi.Disconnect() if err != nil { log.Printf("WiFi disconnect error: %v", err) logging.AddLog("WiFi", "Erreur de déconnexion") c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur de déconnexion"}) return } logging.AddLog("WiFi", "Déconnexion réussie") c.JSON(http.StatusOK, gin.H{"status": "success"}) } // ConfigureHotspot handles hotspot configuration func ConfigureHotspot(c *gin.Context) { var config models.HotspotConfig if err := c.ShouldBindJSON(&config); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Données invalides"}) return } err := hotspot.Configure(config) if err != nil { log.Printf("Hotspot configure error: %v", err) logging.AddLog("Hotspot", "Erreur de configuration") // Validation errors are user-actionable; keep them on the wire. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } logging.AddLog("Hotspot", "Configuration mise à jour") c.JSON(http.StatusOK, gin.H{"status": "success"}) } // ToggleHotspot handles hotspot enable/disable func ToggleHotspot(c *gin.Context, status *models.SystemStatus, statusMu *sync.RWMutex) { // Determine current state under read lock to avoid racing with the // periodic status updater that mutates HotspotStatus. statusMu.RLock() isEnabled := status.HotspotStatus != nil && status.HotspotStatus.State == "ENABLED" statusMu.RUnlock() var err error if !isEnabled { err = hotspot.Start() logging.AddLog("Hotspot", "Hotspot activé") } else { err = hotspot.Stop() logging.AddLog("Hotspot", "Hotspot désactivé") } if err != nil { log.Printf("Hotspot toggle error: %v", err) logging.AddLog("Hotspot", "Erreur") c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur"}) return } // Refresh status under the write lock; the periodic updater touches // the same field on a 5s ticker. newStatus := hotspot.GetDetailedStatus() statusMu.Lock() status.HotspotStatus = newStatus statusMu.Unlock() c.JSON(http.StatusOK, gin.H{"enabled": !isEnabled}) } // GetDevices returns connected devices func GetDevices(c *gin.Context, cfg *config.Config) { devices, err := station.GetStations() if err != nil { log.Printf("GetDevices error: %v", err) logging.AddLog("Système", "Erreur lors de la récupération des appareils") c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur lors de la récupération des appareils"}) return } c.JSON(http.StatusOK, devices) } // GetStatus returns system status. Reads under the shared lock so the JSON // encoder doesn't observe a torn ConnectedDevices slice mid-update. func GetStatus(c *gin.Context, status *models.SystemStatus, statusMu *sync.RWMutex) { statusMu.RLock() snapshot := *status statusMu.RUnlock() c.JSON(http.StatusOK, snapshot) } // GetLogs returns system logs func GetLogs(c *gin.Context) { logs := logging.GetLogs() c.JSON(http.StatusOK, logs) } // ClearLogs clears system logs func ClearLogs(c *gin.Context) { logging.ClearLogs() c.JSON(http.StatusOK, gin.H{"status": "success"}) }