Migrate to a better architectured project

This commit is contained in:
nemunaire 2025-10-28 19:23:27 +07:00
commit b1b9eaa028
21 changed files with 2712 additions and 1540 deletions

View file

@ -0,0 +1,132 @@
package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/nemunaire/repeater/internal/device"
"github.com/nemunaire/repeater/internal/hotspot"
"github.com/nemunaire/repeater/internal/logging"
"github.com/nemunaire/repeater/internal/models"
"github.com/nemunaire/repeater/internal/wifi"
)
// ScanWiFi handles WiFi network scanning
func ScanWiFi(c *gin.Context) {
networks, err := wifi.ScanNetworks()
if err != nil {
logging.AddLog("WiFi", "Erreur lors du scan: "+err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur lors du scan WiFi"})
return
}
logging.AddLog("WiFi", "Scan terminé - "+string(rune(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 à "+req.SSID)
err := wifi.Connect(req.SSID, req.Password)
if err != nil {
logging.AddLog("WiFi", "Échec de connexion: "+err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "Échec de connexion: " + err.Error()})
return
}
logging.AddLog("WiFi", "Connexion réussie à "+req.SSID)
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 {
logging.AddLog("WiFi", "Erreur de déconnexion: "+err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur de déconnexion: " + err.Error()})
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 {
logging.AddLog("Hotspot", "Erreur de configuration: "+err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur de configuration: " + err.Error()})
return
}
logging.AddLog("Hotspot", "Configuration mise à jour: "+config.SSID)
c.JSON(http.StatusOK, gin.H{"status": "success"})
}
// ToggleHotspot handles hotspot enable/disable
func ToggleHotspot(c *gin.Context, status *models.SystemStatus) {
status.HotspotEnabled = !status.HotspotEnabled
enabled := status.HotspotEnabled
var err error
if enabled {
err = hotspot.Start()
logging.AddLog("Hotspot", "Hotspot activé")
} else {
err = hotspot.Stop()
logging.AddLog("Hotspot", "Hotspot désactivé")
}
if err != nil {
logging.AddLog("Hotspot", "Erreur: "+err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"enabled": enabled})
}
// GetDevices returns connected devices
func GetDevices(c *gin.Context) {
devices, err := device.GetConnectedDevices()
if err != nil {
logging.AddLog("Système", "Erreur lors de la récupération des appareils: "+err.Error())
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
func GetStatus(c *gin.Context, status *models.SystemStatus) {
c.JSON(http.StatusOK, status)
}
// 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"})
}

View file

@ -0,0 +1,38 @@
package handlers
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/nemunaire/repeater/internal/logging"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// WebSocketLogs handles WebSocket connections for real-time logs
func WebSocketLogs(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Printf("Erreur WebSocket: %v", err)
return
}
defer conn.Close()
// Register client
logging.RegisterWebSocketClient(conn)
defer logging.UnregisterWebSocketClient(conn)
// Keep connection alive
for {
_, _, err := conn.ReadMessage()
if err != nil {
break
}
}
}

64
internal/api/router.go Normal file
View file

@ -0,0 +1,64 @@
package api
import (
"embed"
"io/fs"
"net/http"
"github.com/gin-gonic/gin"
"github.com/nemunaire/repeater/internal/api/handlers"
"github.com/nemunaire/repeater/internal/models"
)
// SetupRouter creates and configures the Gin router
func SetupRouter(status *models.SystemStatus, assets embed.FS) *gin.Engine {
// Set Gin to release mode (can be overridden with GIN_MODE env var)
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
// API routes
api := r.Group("/api")
{
// WiFi endpoints
wifi := api.Group("/wifi")
{
wifi.GET("/scan", handlers.ScanWiFi)
wifi.POST("/connect", handlers.ConnectWiFi)
wifi.POST("/disconnect", handlers.DisconnectWiFi)
}
// Hotspot endpoints
hotspot := api.Group("/hotspot")
{
hotspot.POST("/config", handlers.ConfigureHotspot)
hotspot.POST("/toggle", func(c *gin.Context) {
handlers.ToggleHotspot(c, status)
})
}
// Device endpoints
api.GET("/devices", handlers.GetDevices)
// Status endpoint
api.GET("/status", func(c *gin.Context) {
handlers.GetStatus(c, status)
})
// Log endpoints
api.GET("/logs", handlers.GetLogs)
api.DELETE("/logs", handlers.ClearLogs)
}
// WebSocket endpoint
r.GET("/ws/logs", handlers.WebSocketLogs)
// Serve static files
sub, err := fs.Sub(assets, "static")
if err != nil {
panic("Unable to access static directory: " + err.Error())
}
r.NoRoute(gin.WrapH(http.FileServer(http.FS(sub))))
return r
}