mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-10 07:25:37 -05:00
233 lines
5.0 KiB
Go
233 lines
5.0 KiB
Go
package network
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
)
|
|
|
|
const (
|
|
iwdBusName = "net.connman.iwd"
|
|
iwdObjectPath = "/"
|
|
iwdAdapterInterface = "net.connman.iwd.Adapter"
|
|
iwdDeviceInterface = "net.connman.iwd.Device"
|
|
iwdStationInterface = "net.connman.iwd.Station"
|
|
iwdNetworkInterface = "net.connman.iwd.Network"
|
|
iwdKnownNetworkInterface = "net.connman.iwd.KnownNetwork"
|
|
dbusObjectManager = "org.freedesktop.DBus.ObjectManager"
|
|
dbusPropertiesInterface = "org.freedesktop.DBus.Properties"
|
|
)
|
|
|
|
type connectAttempt struct {
|
|
ssid string
|
|
netPath dbus.ObjectPath
|
|
start time.Time
|
|
deadline time.Time
|
|
sawAuthish bool
|
|
connectedAt time.Time
|
|
sawIPConfig bool
|
|
sawPromptRetry bool
|
|
finalized bool
|
|
mu sync.Mutex
|
|
}
|
|
|
|
type IWDBackend struct {
|
|
conn *dbus.Conn
|
|
state *BackendState
|
|
stateMutex sync.RWMutex
|
|
promptBroker PromptBroker
|
|
onStateChange func()
|
|
|
|
devicePath dbus.ObjectPath
|
|
stationPath dbus.ObjectPath
|
|
adapterPath dbus.ObjectPath
|
|
|
|
iwdAgent *IWDAgent
|
|
|
|
stopChan chan struct{}
|
|
sigWG sync.WaitGroup
|
|
curAttempt *connectAttempt
|
|
attemptMutex sync.RWMutex
|
|
recentScans map[string]time.Time
|
|
recentScansMu sync.Mutex
|
|
}
|
|
|
|
func NewIWDBackend() (*IWDBackend, error) {
|
|
backend := &IWDBackend{
|
|
state: &BackendState{
|
|
Backend: "iwd",
|
|
WiFiEnabled: true,
|
|
},
|
|
stopChan: make(chan struct{}),
|
|
recentScans: make(map[string]time.Time),
|
|
}
|
|
|
|
return backend, nil
|
|
}
|
|
|
|
func (b *IWDBackend) Initialize() error {
|
|
conn, err := dbus.ConnectSystemBus()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to connect to system bus: %w", err)
|
|
}
|
|
b.conn = conn
|
|
|
|
if err := b.discoverDevices(); err != nil {
|
|
conn.Close()
|
|
return fmt.Errorf("failed to discover iwd devices: %w", err)
|
|
}
|
|
|
|
if err := b.updateState(); err != nil {
|
|
conn.Close()
|
|
return fmt.Errorf("failed to get initial state: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *IWDBackend) Close() {
|
|
close(b.stopChan)
|
|
b.sigWG.Wait()
|
|
|
|
if b.iwdAgent != nil {
|
|
b.iwdAgent.Close()
|
|
}
|
|
|
|
if b.conn != nil {
|
|
b.conn.Close()
|
|
}
|
|
}
|
|
|
|
func (b *IWDBackend) discoverDevices() error {
|
|
obj := b.conn.Object(iwdBusName, iwdObjectPath)
|
|
|
|
var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
|
|
err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get managed objects: %w", err)
|
|
}
|
|
|
|
for path, interfaces := range objects {
|
|
if _, hasStation := interfaces[iwdStationInterface]; hasStation {
|
|
b.stationPath = path
|
|
}
|
|
if _, hasDevice := interfaces[iwdDeviceInterface]; hasDevice {
|
|
b.devicePath = path
|
|
|
|
if devProps, ok := interfaces[iwdDeviceInterface]; ok {
|
|
if nameVar, ok := devProps["Name"]; ok {
|
|
if name, ok := nameVar.Value().(string); ok {
|
|
b.stateMutex.Lock()
|
|
b.state.WiFiDevice = name
|
|
b.stateMutex.Unlock()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if _, hasAdapter := interfaces[iwdAdapterInterface]; hasAdapter {
|
|
b.adapterPath = path
|
|
}
|
|
}
|
|
|
|
if b.stationPath == "" || b.devicePath == "" {
|
|
return fmt.Errorf("no WiFi device found")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *IWDBackend) GetCurrentState() (*BackendState, error) {
|
|
state := *b.state
|
|
state.WiFiNetworks = append([]WiFiNetwork(nil), b.state.WiFiNetworks...)
|
|
state.WiredConnections = append([]WiredConnection(nil), b.state.WiredConnections...)
|
|
|
|
return &state, nil
|
|
}
|
|
|
|
func (b *IWDBackend) OnUserCanceledPrompt() {
|
|
b.stateMutex.RLock()
|
|
cancelledSSID := b.state.ConnectingSSID
|
|
b.stateMutex.RUnlock()
|
|
|
|
b.setConnectError("user-canceled")
|
|
|
|
if cancelledSSID != "" {
|
|
if err := b.ForgetWiFiNetwork(cancelledSSID); err != nil {
|
|
}
|
|
}
|
|
|
|
if b.onStateChange != nil {
|
|
b.onStateChange()
|
|
}
|
|
}
|
|
|
|
func (b *IWDBackend) OnPromptRetry(ssid string) {
|
|
b.attemptMutex.RLock()
|
|
att := b.curAttempt
|
|
b.attemptMutex.RUnlock()
|
|
|
|
if att != nil && att.ssid == ssid {
|
|
att.mu.Lock()
|
|
att.sawPromptRetry = true
|
|
att.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
func (b *IWDBackend) MarkIPConfigSeen() {
|
|
b.attemptMutex.RLock()
|
|
att := b.curAttempt
|
|
b.attemptMutex.RUnlock()
|
|
if att != nil {
|
|
att.mu.Lock()
|
|
att.sawIPConfig = true
|
|
att.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
func (b *IWDBackend) GetPromptBroker() PromptBroker {
|
|
return b.promptBroker
|
|
}
|
|
|
|
func (b *IWDBackend) SetPromptBroker(broker PromptBroker) error {
|
|
if broker == nil {
|
|
return fmt.Errorf("broker cannot be nil")
|
|
}
|
|
|
|
b.promptBroker = broker
|
|
return nil
|
|
}
|
|
|
|
func (b *IWDBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error {
|
|
if b.promptBroker == nil {
|
|
return fmt.Errorf("prompt broker not initialized")
|
|
}
|
|
|
|
return b.promptBroker.Resolve(token, PromptReply{
|
|
Secrets: secrets,
|
|
Save: save,
|
|
Cancel: false,
|
|
})
|
|
}
|
|
|
|
func (b *IWDBackend) CancelCredentials(token string) error {
|
|
if b.promptBroker == nil {
|
|
return fmt.Errorf("prompt broker not initialized")
|
|
}
|
|
|
|
return b.promptBroker.Resolve(token, PromptReply{
|
|
Cancel: true,
|
|
})
|
|
}
|
|
|
|
func (b *IWDBackend) StopMonitoring() {
|
|
select {
|
|
case <-b.stopChan:
|
|
return
|
|
default:
|
|
close(b.stopChan)
|
|
}
|
|
b.sigWG.Wait()
|
|
}
|