app: Surface Ethernet uplink in the UI and gate wpa_supplicant access

When the configured Ethernet interface holds a DHCP-assigned IPv4 at
startup, the app now skips wifi.Initialize / StartEventMonitoring and
guards every wifi.* wrapper against a nil backend. This prevents D-Bus
calls to fi.w1.wpa_supplicant1 from re-activating the daemon via
dbus-activation, honoring the "do nothing" intent of the Ethernet path.

The probed state is exposed in SystemStatus and rendered in the header
as a third pill ("Ethernet · <IP>"); a new "disabled" connectionState
covers the WiFi pill in this mode.
This commit is contained in:
nemunaire 2026-05-02 11:24:36 +08:00
commit 8b1debdddc
7 changed files with 166 additions and 37 deletions

View file

@ -57,20 +57,28 @@ func (a *App) Initialize(cfg *config.Config) error {
// Store config reference
a.Config = cfg
// If Ethernet uplink is not already providing connectivity (no DHCP lease
// on the configured interface), bring up wpa_supplicant so the WiFi
// backend has something to talk to.
ensureUplink(cfg.EthernetInterface)
// Decide whether the Ethernet uplink already provides connectivity. When
// it does we deliberately skip every wpa_supplicant interaction below —
// the daemon is dbus-activatable, so any call into the WiFi backend
// would re-spawn it and undo this choice.
eth := ensureUplink(cfg.EthernetInterface)
a.StatusMutex.Lock()
a.Status.EthernetStatus = eth
a.StatusMutex.Unlock()
// Initialize WiFi backend
if err := wifi.Initialize(cfg.WifiInterface, cfg.WifiBackend); err != nil {
return err
}
if !eth.Active {
// Initialize WiFi backend
if err := wifi.Initialize(cfg.WifiInterface, cfg.WifiBackend); err != nil {
return err
}
// Start WiFi event monitoring
if err := wifi.StartEventMonitoring(); err != nil {
log.Printf("Warning: WiFi event monitoring failed: %v", err)
// Don't fail - polling fallback still works
// Start WiFi event monitoring
if err := wifi.StartEventMonitoring(); err != nil {
log.Printf("Warning: WiFi event monitoring failed: %v", err)
// Don't fail - polling fallback still works
}
} else {
log.Printf("Skipping WiFi backend init: Ethernet uplink active on %s", eth.Interface)
}
// Initialize station backend
@ -210,10 +218,32 @@ func (a *App) periodicStatusUpdate() {
case <-ticker.C:
}
var eth *models.EthernetStatus
if a.Config != nil {
if e, err := probeEthernet(a.Config.EthernetInterface); err == nil {
eth = e
}
}
a.StatusMutex.Lock()
a.Status.Connected = wifi.IsConnected()
a.Status.ConnectionState = wifi.GetConnectionState()
a.Status.ConnectedSSID = wifi.GetConnectedSSID()
if eth != nil {
a.Status.EthernetStatus = eth
}
// Skip every wifi.* call when the Ethernet uplink is the chosen
// path: the WiFi backend isn't initialized in that mode and the
// wrappers would otherwise return zero values; either way we don't
// want to risk dbus-activating wpa_supplicant from this hot loop.
ethActive := a.Status.EthernetStatus != nil && a.Status.EthernetStatus.Active
if !ethActive {
a.Status.Connected = wifi.IsConnected()
a.Status.ConnectionState = wifi.GetConnectionState()
a.Status.ConnectedSSID = wifi.GetConnectedSSID()
} else {
a.Status.Connected = false
a.Status.ConnectionState = "disabled"
a.Status.ConnectedSSID = ""
}
a.Status.Uptime = getSystemUptime()
// Get detailed hotspot status