repeater/internal/wifi/wifi.go

242 lines
6 KiB
Go

package wifi
import (
"fmt"
"sort"
"strings"
"time"
"github.com/gorilla/websocket"
"github.com/nemunaire/repeater/internal/models"
"github.com/nemunaire/repeater/internal/wifi/backend"
)
var (
wifiBackend backend.WiFiBackend
wifiBroadcaster *WifiBroadcaster
)
// Initialize initializes the WiFi service with the specified backend
func Initialize(interfaceName string, backendName string) error {
// Create the appropriate backend using the factory
var err error
wifiBackend, err = createBackend(backendName)
if err != nil {
return err
}
// Initialize the backend
return wifiBackend.Initialize(interfaceName)
}
// Close closes the backend connection
func Close() {
if wifiBackend != nil {
wifiBackend.Close()
}
}
// GetCachedNetworks returns previously discovered networks without triggering a scan
func GetCachedNetworks() ([]models.WiFiNetwork, error) {
// Get ordered networks from backend
backendNetworks, err := wifiBackend.GetOrderedNetworks()
if err != nil {
return nil, fmt.Errorf("erreur lors de la récupération des réseaux: %v", err)
}
// Convert backend networks to models
networks := make([]models.WiFiNetwork, 0, len(backendNetworks))
for _, backendNet := range backendNetworks {
wifiNet := models.WiFiNetwork{
SSID: backendNet.SSID,
Signal: signalToStrength(int(backendNet.SignalDBm)),
Security: mapSecurityType(backendNet.SecurityType),
BSSID: backendNet.BSSID,
Channel: 0, // Not yet exposed by backends
}
networks = append(networks, wifiNet)
}
// Sort by signal strength (descending)
sort.Slice(networks, func(i, j int) bool {
return networks[i].Signal > networks[j].Signal
})
return networks, nil
}
// ScanNetworks scans for available WiFi networks
func ScanNetworks() ([]models.WiFiNetwork, error) {
// Check if already scanning
scanning, err := wifiBackend.IsScanning()
if err == nil && scanning {
time.Sleep(3 * time.Second)
} else {
// Trigger scan
err := wifiBackend.ScanNetworks()
if err != nil && !strings.Contains(err.Error(), "rejected") {
return nil, fmt.Errorf("erreur lors du scan: %v", err)
}
time.Sleep(2 * time.Second)
}
// Get ordered networks from backend
backendNetworks, err := wifiBackend.GetOrderedNetworks()
if err != nil {
return nil, fmt.Errorf("erreur lors de la récupération des réseaux: %v", err)
}
// Convert backend networks to models
networks := make([]models.WiFiNetwork, 0, len(backendNetworks))
for _, backendNet := range backendNetworks {
wifiNet := models.WiFiNetwork{
SSID: backendNet.SSID,
Signal: signalToStrength(int(backendNet.SignalDBm)),
Security: mapSecurityType(backendNet.SecurityType),
BSSID: backendNet.BSSID,
Channel: 0, // Not yet exposed by backends
}
networks = append(networks, wifiNet)
}
// Sort by signal strength (descending)
sort.Slice(networks, func(i, j int) bool {
return networks[i].Signal > networks[j].Signal
})
// Broadcast to WebSocket clients if available
if wifiBroadcaster != nil {
wifiBroadcaster.BroadcastScanUpdate(networks)
}
return networks, nil
}
// Connect connects to a WiFi network
func Connect(ssid, password string) error {
// Use backend to connect
if err := wifiBackend.Connect(ssid, password); err != nil {
return err
}
// Poll for connection
for i := 0; i < 20; i++ {
time.Sleep(500 * time.Millisecond)
if IsConnected() {
return nil
}
}
return fmt.Errorf("timeout lors de la connexion")
}
// Disconnect disconnects from the current WiFi network
func Disconnect() error {
return wifiBackend.Disconnect()
}
// IsConnected checks if WiFi is connected
func IsConnected() bool {
state, err := wifiBackend.GetConnectionState()
if err != nil {
return false
}
return state == backend.StateConnected
}
// GetConnectedSSID returns the SSID of the currently connected network
func GetConnectedSSID() string {
return wifiBackend.GetConnectedSSID()
}
// GetConnectionState returns the current WiFi connection state
func GetConnectionState() string {
state, err := wifiBackend.GetConnectionState()
if err != nil {
return string(backend.StateDisconnected)
}
return string(state)
}
// StartEventMonitoring initializes signal monitoring and WebSocket broadcasting
func StartEventMonitoring() error {
// Initialize broadcaster
wifiBroadcaster = NewWifiBroadcaster()
// Set up callbacks
callbacks := backend.EventCallbacks{
OnStateChange: handleStateChange,
OnScanComplete: handleScanComplete,
}
// Start backend monitoring
return wifiBackend.StartEventMonitoring(callbacks)
}
// StopEventMonitoring stops signal monitoring
func StopEventMonitoring() {
if wifiBackend != nil {
wifiBackend.StopEventMonitoring()
}
}
// RegisterWebSocketClient registers a new WebSocket client for WiFi events
func RegisterWebSocketClient(conn *websocket.Conn) {
if wifiBroadcaster != nil {
wifiBroadcaster.RegisterClient(conn)
}
}
// UnregisterWebSocketClient removes a WebSocket client
func UnregisterWebSocketClient(conn *websocket.Conn) {
if wifiBroadcaster != nil {
wifiBroadcaster.UnregisterClient(conn)
}
}
// handleStateChange is called when WiFi connection state changes
func handleStateChange(newState backend.ConnectionState, connectedSSID string) {
if wifiBroadcaster != nil {
wifiBroadcaster.BroadcastStateChange(string(newState), connectedSSID)
}
}
// handleScanComplete is called when a WiFi scan completes
func handleScanComplete() {
// Get updated network list
networks, err := GetCachedNetworks()
if err == nil && wifiBroadcaster != nil {
wifiBroadcaster.BroadcastScanUpdate(networks)
}
}
// mapSecurityType maps backend security types to display format
func mapSecurityType(securityType string) string {
switch securityType {
case "open":
return "Open"
case "wep":
return "WEP"
case "psk":
return "WPA2"
case "8021x":
return "WPA2"
default:
return "WPA2"
}
}
// signalToStrength converts signal level (dBm) to strength (1-5)
func signalToStrength(level int) int {
if level >= -30 {
return 5
} else if level >= -50 {
return 4
} else if level >= -60 {
return 3
} else if level >= -70 {
return 2
} else {
return 1
}
}