1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-10 07:25:37 -05:00
Files
DankMaterialShell/backend/internal/server/network/backend_iwd_signals.go
2025-11-12 17:18:45 -05:00

356 lines
9.5 KiB
Go

package network
import (
"fmt"
"time"
"github.com/godbus/dbus/v5"
)
func (b *IWDBackend) StartMonitoring(onStateChange func()) error {
b.onStateChange = onStateChange
if b.promptBroker != nil {
agent, err := NewIWDAgent(b.conn, b.promptBroker)
if err != nil {
return fmt.Errorf("failed to start IWD agent: %w", err)
}
agent.onUserCanceled = b.OnUserCanceledPrompt
agent.onPromptRetry = b.OnPromptRetry
b.iwdAgent = agent
}
sigChan := make(chan *dbus.Signal, 100)
b.conn.Signal(sigChan)
if b.devicePath != "" {
err := b.conn.AddMatchSignal(
dbus.WithMatchObjectPath(b.devicePath),
dbus.WithMatchInterface(dbusPropertiesInterface),
dbus.WithMatchMember("PropertiesChanged"),
)
if err != nil {
return fmt.Errorf("failed to add device signal match: %w", err)
}
}
if b.stationPath != "" {
err := b.conn.AddMatchSignal(
dbus.WithMatchObjectPath(b.stationPath),
dbus.WithMatchInterface(dbusPropertiesInterface),
dbus.WithMatchMember("PropertiesChanged"),
)
if err != nil {
return fmt.Errorf("failed to add station signal match: %w", err)
}
}
b.sigWG.Add(1)
go b.signalHandler(sigChan)
return nil
}
func (b *IWDBackend) signalHandler(sigChan chan *dbus.Signal) {
defer b.sigWG.Done()
for {
select {
case <-b.stopChan:
b.conn.RemoveSignal(sigChan)
close(sigChan)
return
case sig := <-sigChan:
if sig == nil {
return
}
if sig.Name != dbusPropertiesInterface+".PropertiesChanged" {
continue
}
if len(sig.Body) < 2 {
continue
}
iface, ok := sig.Body[0].(string)
if !ok {
continue
}
changed, ok := sig.Body[1].(map[string]dbus.Variant)
if !ok {
continue
}
stateChanged := false
switch iface {
case iwdDeviceInterface:
if sig.Path == b.devicePath {
if poweredVar, ok := changed["Powered"]; ok {
if powered, ok := poweredVar.Value().(bool); ok {
b.stateMutex.Lock()
if b.state.WiFiEnabled != powered {
b.state.WiFiEnabled = powered
stateChanged = true
}
b.stateMutex.Unlock()
}
}
}
case iwdStationInterface:
if sig.Path == b.stationPath {
if scanningVar, ok := changed["Scanning"]; ok {
if scanning, ok := scanningVar.Value().(bool); ok && !scanning {
networks, err := b.updateWiFiNetworks()
if err == nil {
b.stateMutex.Lock()
b.state.WiFiNetworks = networks
b.stateMutex.Unlock()
stateChanged = true
}
b.stateMutex.RLock()
wifiConnected := b.state.WiFiConnected
b.stateMutex.RUnlock()
if wifiConnected {
stationObj := b.conn.Object(iwdBusName, b.stationPath)
connNetVar, err := stationObj.GetProperty(iwdStationInterface + ".ConnectedNetwork")
if err == nil && connNetVar.Value() != nil {
if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" {
var orderedNetworks [][]dbus.Variant
err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks)
if err == nil {
for _, netData := range orderedNetworks {
if len(netData) < 2 {
continue
}
currentNetPath, ok := netData[0].Value().(dbus.ObjectPath)
if !ok || currentNetPath != netPath {
continue
}
signalStrength, ok := netData[1].Value().(int16)
if !ok {
continue
}
signalDbm := signalStrength / 100
signal := uint8(signalDbm + 100)
if signalDbm > 0 {
signal = 100
} else if signalDbm < -100 {
signal = 0
}
b.stateMutex.Lock()
if b.state.WiFiSignal != signal {
b.state.WiFiSignal = signal
stateChanged = true
}
b.stateMutex.Unlock()
break
}
}
}
}
}
}
}
if stateVar, ok := changed["State"]; ok {
if state, ok := stateVar.Value().(string); ok {
b.attemptMutex.RLock()
att := b.curAttempt
b.attemptMutex.RUnlock()
var connPath dbus.ObjectPath
if v, ok := changed["ConnectedNetwork"]; ok {
if v.Value() != nil {
if p, ok := v.Value().(dbus.ObjectPath); ok {
connPath = p
}
}
}
if connPath == "" {
station := b.conn.Object(iwdBusName, b.stationPath)
if cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork"); err == nil && cnVar.Value() != nil {
cnVar.Store(&connPath)
}
}
b.stateMutex.RLock()
prevConnected := b.state.WiFiConnected
prevSSID := b.state.WiFiSSID
b.stateMutex.RUnlock()
targetPath := dbus.ObjectPath("")
if att != nil {
targetPath = att.netPath
}
isTarget := att != nil && targetPath != "" && connPath == targetPath
if att != nil {
switch state {
case "authenticating", "associating", "associated", "roaming":
att.mu.Lock()
att.sawAuthish = true
att.mu.Unlock()
}
}
if att != nil && state == "connected" && isTarget {
att.mu.Lock()
if att.connectedAt.IsZero() {
att.connectedAt = time.Now()
}
att.mu.Unlock()
}
if att != nil && state == "configuring" {
att.mu.Lock()
att.sawIPConfig = true
att.mu.Unlock()
}
switch state {
case "connected":
b.stateMutex.Lock()
b.state.WiFiConnected = true
b.state.NetworkStatus = StatusWiFi
b.state.IsConnecting = false
b.state.ConnectingSSID = ""
b.state.LastError = ""
b.stateMutex.Unlock()
if connPath != "" && connPath != "/" {
netObj := b.conn.Object(iwdBusName, connPath)
if nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name"); err == nil {
if name, ok := nameVar.Value().(string); ok {
b.stateMutex.Lock()
b.state.WiFiSSID = name
b.stateMutex.Unlock()
}
}
}
stateChanged = true
if att != nil && isTarget {
go func(attLocal *connectAttempt, tgt dbus.ObjectPath) {
time.Sleep(3 * time.Second)
station := b.conn.Object(iwdBusName, b.stationPath)
var nowState string
if stVar, err := station.GetProperty(iwdStationInterface + ".State"); err == nil {
stVar.Store(&nowState)
}
var nowConn dbus.ObjectPath
if cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork"); err == nil && cnVar.Value() != nil {
cnVar.Store(&nowConn)
}
if nowState == "connected" && nowConn == tgt {
b.finalizeAttempt(attLocal, "")
b.attemptMutex.Lock()
if b.curAttempt == attLocal {
b.curAttempt = nil
}
b.attemptMutex.Unlock()
}
}(att, targetPath)
}
case "disconnecting", "disconnected":
if att != nil {
wasConnectedToTarget := prevConnected && prevSSID == att.ssid
if wasConnectedToTarget || isTarget {
code := b.classifyAttempt(att)
b.finalizeAttempt(att, code)
b.attemptMutex.Lock()
if b.curAttempt == att {
b.curAttempt = nil
}
b.attemptMutex.Unlock()
}
}
b.stateMutex.Lock()
b.state.WiFiConnected = false
if state == "disconnected" {
b.state.NetworkStatus = StatusDisconnected
}
b.stateMutex.Unlock()
stateChanged = true
}
}
}
if connNetVar, ok := changed["ConnectedNetwork"]; ok {
if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" {
netObj := b.conn.Object(iwdBusName, netPath)
nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name")
if err == nil {
if name, ok := nameVar.Value().(string); ok {
b.stateMutex.Lock()
if b.state.WiFiSSID != name {
b.state.WiFiSSID = name
stateChanged = true
}
b.stateMutex.Unlock()
}
}
stationObj := b.conn.Object(iwdBusName, b.stationPath)
var orderedNetworks [][]dbus.Variant
err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks)
if err == nil {
for _, netData := range orderedNetworks {
if len(netData) < 2 {
continue
}
currentNetPath, ok := netData[0].Value().(dbus.ObjectPath)
if !ok || currentNetPath != netPath {
continue
}
signalStrength, ok := netData[1].Value().(int16)
if !ok {
continue
}
signalDbm := signalStrength / 100
signal := uint8(signalDbm + 100)
if signalDbm > 0 {
signal = 100
} else if signalDbm < -100 {
signal = 0
}
b.stateMutex.Lock()
if b.state.WiFiSignal != signal {
b.state.WiFiSignal = signal
stateChanged = true
}
b.stateMutex.Unlock()
break
}
}
} else {
b.stateMutex.Lock()
if b.state.WiFiSSID != "" {
b.state.WiFiSSID = ""
b.state.WiFiSignal = 0
stateChanged = true
}
b.stateMutex.Unlock()
}
}
}
}
if stateChanged && b.onStateChange != nil {
b.onStateChange()
}
}
}
}