Create wifi backend abstraction
This commit is contained in:
parent
f4481bca62
commit
79c28da9c5
7 changed files with 401 additions and 174 deletions
|
|
@ -6,102 +6,54 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/nemunaire/repeater/internal/models"
|
||||
"github.com/nemunaire/repeater/internal/wifi/iwd"
|
||||
)
|
||||
|
||||
const (
|
||||
AGENT_PATH = "/com/github/nemunaire/repeater/agent"
|
||||
"github.com/nemunaire/repeater/internal/wifi/backend"
|
||||
)
|
||||
|
||||
var (
|
||||
wlanInterface string
|
||||
dbusConn *dbus.Conn
|
||||
iwdManager *iwd.Manager
|
||||
station *iwd.Station
|
||||
agent *iwd.Agent
|
||||
agentManager *iwd.AgentManager
|
||||
eventMonitor *iwd.SignalMonitor
|
||||
wifiBackend backend.WiFiBackend
|
||||
wifiBroadcaster *WifiBroadcaster
|
||||
)
|
||||
|
||||
// Initialize initializes the WiFi service with iwd D-Bus connection
|
||||
func Initialize(interfaceName string) error {
|
||||
wlanInterface = interfaceName
|
||||
// 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
|
||||
|
||||
// Connect to D-Bus
|
||||
dbusConn, err = dbus.SystemBus()
|
||||
wifiBackend, err = createBackend(backendName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("échec de connexion à D-Bus: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Find station for interface
|
||||
iwdManager = iwd.NewManager(dbusConn)
|
||||
station, err = iwdManager.FindStation(interfaceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("impossible de trouver la station pour %s: %v", interfaceName, err)
|
||||
}
|
||||
|
||||
// Create and register agent for credential callbacks
|
||||
agent = iwd.NewAgent(dbusConn, dbus.ObjectPath(AGENT_PATH))
|
||||
if err := agent.Export(); err != nil {
|
||||
return fmt.Errorf("échec de l'export de l'agent: %v", err)
|
||||
}
|
||||
|
||||
agentManager = iwd.NewAgentManager(dbusConn)
|
||||
if err := agentManager.RegisterAgent(dbus.ObjectPath(AGENT_PATH)); err != nil {
|
||||
agent.Unexport()
|
||||
return fmt.Errorf("échec de l'enregistrement de l'agent: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
// Initialize the backend
|
||||
return wifiBackend.Initialize(interfaceName)
|
||||
}
|
||||
|
||||
// Close closes the D-Bus connection and unregisters the agent
|
||||
// Close closes the backend connection
|
||||
func Close() {
|
||||
if agentManager != nil && agent != nil {
|
||||
agentManager.UnregisterAgent(dbus.ObjectPath(AGENT_PATH))
|
||||
agent.Unexport()
|
||||
}
|
||||
if dbusConn != nil {
|
||||
dbusConn.Close()
|
||||
if wifiBackend != nil {
|
||||
wifiBackend.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// GetCachedNetworks returns previously discovered networks without triggering a scan
|
||||
func GetCachedNetworks() ([]models.WiFiNetwork, error) {
|
||||
// Get ordered networks without scanning
|
||||
networkInfos, err := station.GetOrderedNetworks()
|
||||
// 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)
|
||||
}
|
||||
|
||||
var networks []models.WiFiNetwork
|
||||
seenSSIDs := make(map[string]bool)
|
||||
|
||||
for _, netInfo := range networkInfos {
|
||||
network := iwd.NewNetwork(dbusConn, netInfo.Path)
|
||||
props, err := network.GetProperties()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if props.Name == "" || seenSSIDs[props.Name] {
|
||||
continue
|
||||
}
|
||||
seenSSIDs[props.Name] = true
|
||||
|
||||
// Convert backend networks to models
|
||||
networks := make([]models.WiFiNetwork, 0, len(backendNetworks))
|
||||
for _, backendNet := range backendNetworks {
|
||||
wifiNet := models.WiFiNetwork{
|
||||
SSID: props.Name,
|
||||
Signal: signalToStrength(int(netInfo.Signal) / 100),
|
||||
Security: mapSecurityType(props.Type),
|
||||
BSSID: generateSyntheticBSSID(props.Name),
|
||||
Channel: 0,
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -116,47 +68,34 @@ func GetCachedNetworks() ([]models.WiFiNetwork, error) {
|
|||
// ScanNetworks scans for available WiFi networks
|
||||
func ScanNetworks() ([]models.WiFiNetwork, error) {
|
||||
// Check if already scanning
|
||||
scanning, err := station.IsScanning()
|
||||
scanning, err := wifiBackend.IsScanning()
|
||||
if err == nil && scanning {
|
||||
time.Sleep(3 * time.Second)
|
||||
} else {
|
||||
// Trigger scan
|
||||
err := station.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
|
||||
networkInfos, err := station.GetOrderedNetworks()
|
||||
// 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)
|
||||
}
|
||||
|
||||
var networks []models.WiFiNetwork
|
||||
seenSSIDs := make(map[string]bool)
|
||||
|
||||
for _, netInfo := range networkInfos {
|
||||
network := iwd.NewNetwork(dbusConn, netInfo.Path)
|
||||
props, err := network.GetProperties()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if props.Name == "" || seenSSIDs[props.Name] {
|
||||
continue
|
||||
}
|
||||
seenSSIDs[props.Name] = true
|
||||
|
||||
// Convert backend networks to models
|
||||
networks := make([]models.WiFiNetwork, 0, len(backendNetworks))
|
||||
for _, backendNet := range backendNetworks {
|
||||
wifiNet := models.WiFiNetwork{
|
||||
SSID: props.Name,
|
||||
Signal: signalToStrength(int(netInfo.Signal) / 100),
|
||||
Security: mapSecurityType(props.Type),
|
||||
BSSID: generateSyntheticBSSID(props.Name),
|
||||
Channel: 0,
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -173,29 +112,11 @@ func ScanNetworks() ([]models.WiFiNetwork, error) {
|
|||
return networks, nil
|
||||
}
|
||||
|
||||
// Connect connects to a WiFi network using iwd agent callback
|
||||
// Connect connects to a WiFi network
|
||||
func Connect(ssid, password string) error {
|
||||
// Store passphrase in agent for callback
|
||||
if password != "" {
|
||||
agent.SetPassphrase(ssid, password)
|
||||
}
|
||||
|
||||
// Ensure passphrase is cleared after connection attempt
|
||||
defer func() {
|
||||
if password != "" {
|
||||
agent.ClearPassphrase(ssid)
|
||||
}
|
||||
}()
|
||||
|
||||
// Get network object
|
||||
network, err := station.GetNetwork(ssid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("réseau '%s' non trouvé: %v", ssid, err)
|
||||
}
|
||||
|
||||
// Connect - iwd will call agent.RequestPassphrase() if needed
|
||||
if err := network.Connect(); err != nil {
|
||||
return fmt.Errorf("erreur lors de la connexion: %v", err)
|
||||
// Use backend to connect
|
||||
if err := wifiBackend.Connect(ssid, password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Poll for connection
|
||||
|
|
@ -211,65 +132,51 @@ func Connect(ssid, password string) error {
|
|||
|
||||
// Disconnect disconnects from the current WiFi network
|
||||
func Disconnect() error {
|
||||
if err := station.Disconnect(); err != nil {
|
||||
return fmt.Errorf("erreur lors de la déconnexion: %v", err)
|
||||
}
|
||||
return nil
|
||||
return wifiBackend.Disconnect()
|
||||
}
|
||||
|
||||
// IsConnected checks if WiFi is connected using iwd
|
||||
// IsConnected checks if WiFi is connected
|
||||
func IsConnected() bool {
|
||||
state, err := station.GetState()
|
||||
state, err := wifiBackend.GetConnectionState()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return state == iwd.StateConnected
|
||||
return state == backend.StateConnected
|
||||
}
|
||||
|
||||
// GetConnectedSSID returns the SSID of the currently connected network
|
||||
func GetConnectedSSID() string {
|
||||
network, err := station.GetConnectedNetwork()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
props, err := network.GetProperties()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return props.Name
|
||||
return wifiBackend.GetConnectedSSID()
|
||||
}
|
||||
|
||||
// GetConnectionState returns the current WiFi connection state
|
||||
func GetConnectionState() string {
|
||||
state, err := station.GetState()
|
||||
state, err := wifiBackend.GetConnectionState()
|
||||
if err != nil {
|
||||
return string(iwd.StateDisconnected)
|
||||
return string(backend.StateDisconnected)
|
||||
}
|
||||
return string(state)
|
||||
}
|
||||
|
||||
// StartEventMonitoring initializes D-Bus signal monitoring and WebSocket broadcasting
|
||||
// StartEventMonitoring initializes signal monitoring and WebSocket broadcasting
|
||||
func StartEventMonitoring() error {
|
||||
// Initialize broadcaster
|
||||
wifiBroadcaster = NewWifiBroadcaster()
|
||||
|
||||
// Create signal monitor
|
||||
eventMonitor = iwd.NewSignalMonitor(dbusConn, station)
|
||||
// Set up callbacks
|
||||
callbacks := backend.EventCallbacks{
|
||||
OnStateChange: handleStateChange,
|
||||
OnScanComplete: handleScanComplete,
|
||||
}
|
||||
|
||||
// Register callbacks
|
||||
eventMonitor.OnStateChange(handleStateChange)
|
||||
eventMonitor.OnScanComplete(handleScanComplete)
|
||||
|
||||
// Start monitoring
|
||||
return eventMonitor.Start()
|
||||
// Start backend monitoring
|
||||
return wifiBackend.StartEventMonitoring(callbacks)
|
||||
}
|
||||
|
||||
// StopEventMonitoring stops D-Bus signal monitoring
|
||||
// StopEventMonitoring stops signal monitoring
|
||||
func StopEventMonitoring() {
|
||||
if eventMonitor != nil {
|
||||
eventMonitor.Stop()
|
||||
if wifiBackend != nil {
|
||||
wifiBackend.StopEventMonitoring()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +195,7 @@ func UnregisterWebSocketClient(conn *websocket.Conn) {
|
|||
}
|
||||
|
||||
// handleStateChange is called when WiFi connection state changes
|
||||
func handleStateChange(newState iwd.StationState, connectedSSID string) {
|
||||
func handleStateChange(newState backend.ConnectionState, connectedSSID string) {
|
||||
if wifiBroadcaster != nil {
|
||||
wifiBroadcaster.BroadcastStateChange(string(newState), connectedSSID)
|
||||
}
|
||||
|
|
@ -303,9 +210,9 @@ func handleScanComplete() {
|
|||
}
|
||||
}
|
||||
|
||||
// mapSecurityType maps iwd security types to display format
|
||||
func mapSecurityType(iwdType string) string {
|
||||
switch iwdType {
|
||||
// mapSecurityType maps backend security types to display format
|
||||
func mapSecurityType(securityType string) string {
|
||||
switch securityType {
|
||||
case "open":
|
||||
return "Open"
|
||||
case "wep":
|
||||
|
|
@ -319,25 +226,6 @@ func mapSecurityType(iwdType string) string {
|
|||
}
|
||||
}
|
||||
|
||||
// generateSyntheticBSSID generates a consistent fake BSSID from SSID
|
||||
func generateSyntheticBSSID(ssid string) string {
|
||||
// Use a simple hash approach - consistent per SSID
|
||||
hash := 0
|
||||
for _, c := range ssid {
|
||||
hash = ((hash << 5) - hash) + int(c)
|
||||
}
|
||||
|
||||
// Generate 6 bytes for MAC address
|
||||
b1 := byte((hash >> 0) & 0xff)
|
||||
b2 := byte((hash >> 8) & 0xff)
|
||||
b3 := byte((hash >> 16) & 0xff)
|
||||
b4 := byte((hash >> 24) & 0xff)
|
||||
b5 := byte(len(ssid) & 0xff)
|
||||
b6 := byte((len(ssid) >> 8) & 0xff)
|
||||
|
||||
return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", b1, b2, b3, b4, b5, b6)
|
||||
}
|
||||
|
||||
// signalToStrength converts signal level (dBm) to strength (1-5)
|
||||
func signalToStrength(level int) int {
|
||||
if level >= -30 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue