mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-13 03:17:54 +08:00
144 lines
3.8 KiB
Diff
144 lines
3.8 KiB
Diff
From 128555126155413ce32b134435c425ad9bb24501 Mon Sep 17 00:00:00 2001
|
|
From: Jackie Han <jackie.han@gmail.com>
|
|
Date: Wed, 14 Oct 2026 07:40:03 +0800
|
|
Subject: [PATCH] Refactor collect function to handle wireless devices
|
|
|
|
---
|
|
agent/wifi/wifi_linux.go | 111 ++++++++++++++++++++++++++++++++++++---
|
|
1 file changed, 105 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/agent/wifi/wifi_linux.go b/agent/wifi/wifi_linux.go
|
|
index 926d658fe..ea42b1f2b 100644
|
|
--- a/agent/wifi/wifi_linux.go
|
|
+++ b/agent/wifi/wifi_linux.go
|
|
@@ -5,8 +5,12 @@ package wifi
|
|
import (
|
|
"context"
|
|
"errors"
|
|
+ "math"
|
|
"net"
|
|
"os"
|
|
+ "os/exec"
|
|
+ "regexp"
|
|
+ "strconv"
|
|
"time"
|
|
|
|
"github.com/henrygd/beszel/internal/entities/system"
|
|
@@ -99,15 +103,110 @@ func hasWirelessDevice(dir string) bool {
|
|
}
|
|
|
|
func collect(ctx context.Context) map[string]system.WiFi {
|
|
- if !hasWirelessDevice(wiphyClassDir) {
|
|
- return nil
|
|
+ results := make(map[string]system.WiFi)
|
|
+
|
|
+ if hasWirelessDevice(wiphyClassDir) {
|
|
+ if client, err := newNL80211Client(); err == nil {
|
|
+ for k, v := range collectLinux(ctx, client) {
|
|
+ results[k] = v
|
|
+ }
|
|
+ client.Close()
|
|
+ }
|
|
}
|
|
- client, err := newNL80211Client()
|
|
- if err != nil {
|
|
+
|
|
+ if _, err := exec.LookPath("iwinfo"); err == nil {
|
|
+ for k, v := range collectOpenWrtAP(ctx) {
|
|
+ results[k] = v
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if len(results) == 0 {
|
|
return nil
|
|
}
|
|
- defer client.Close()
|
|
- return collectLinux(ctx, client)
|
|
+ return results
|
|
+}
|
|
+
|
|
+var (
|
|
+ iwinfoIfaceRe = regexp.MustCompile(`(?m)^(\S+)[ \t]+ESSID:`)
|
|
+ iwinfoModeRe = regexp.MustCompile(`Mode:[ \t]*Master`)
|
|
+ iwinfoSSIDRe = regexp.MustCompile(`ESSID:\s*"([^"]+)"`)
|
|
+ iwinfoAssocRe = regexp.MustCompile(`(?m)^(?:[0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}.*?(-?\d+)\s+dBm`)
|
|
+)
|
|
+
|
|
+type iwinfoBlock struct {
|
|
+ name string
|
|
+ text string
|
|
+}
|
|
+
|
|
+// splitIwinfoBlocks splits bare `iwinfo` output into one block per interface.
|
|
+func splitIwinfoBlocks(out string) []iwinfoBlock {
|
|
+ idx := iwinfoIfaceRe.FindAllStringSubmatchIndex(out, -1)
|
|
+ blocks := make([]iwinfoBlock, 0, len(idx))
|
|
+ for i, m := range idx {
|
|
+ end := len(out)
|
|
+ if i+1 < len(idx) {
|
|
+ end = idx[i+1][0]
|
|
+ }
|
|
+ blocks = append(blocks, iwinfoBlock{name: out[m[2]:m[3]], text: out[m[0]:end]})
|
|
+ }
|
|
+ return blocks
|
|
+}
|
|
+
|
|
+// parseIwinfoInfo reports whether a block is a Master (AP) interface and its SSID.
|
|
+func parseIwinfoInfo(block string) (ssid string, isAP bool) {
|
|
+ if !iwinfoModeRe.MatchString(block) {
|
|
+ return "", false
|
|
+ }
|
|
+ if m := iwinfoSSIDRe.FindStringSubmatch(block); len(m) > 1 {
|
|
+ ssid = m[1]
|
|
+ }
|
|
+ return ssid, true
|
|
+}
|
|
+
|
|
+// parseAssocRSSI returns the rounded average RSSI of associated clients.
|
|
+// ok is false when no valid RSSI value was found.
|
|
+func parseAssocRSSI(out string) (avg float64, ok bool) {
|
|
+ sum, count := 0, 0
|
|
+ for _, m := range iwinfoAssocRe.FindAllStringSubmatch(out, -1) {
|
|
+ rssi, err := strconv.Atoi(m[1])
|
|
+ if err != nil || rssi >= 0 || rssi < -150 {
|
|
+ continue
|
|
+ }
|
|
+ sum += rssi
|
|
+ count++
|
|
+ }
|
|
+ if count == 0 {
|
|
+ return 0, false
|
|
+ }
|
|
+ return math.Round(float64(sum) / float64(count)), true
|
|
+}
|
|
+
|
|
+func collectOpenWrtAP(ctx context.Context) map[string]system.WiFi {
|
|
+ results := make(map[string]system.WiFi)
|
|
+
|
|
+ out, err := exec.CommandContext(ctx, "iwinfo").Output()
|
|
+ if err != nil && len(out) == 0 {
|
|
+ return results
|
|
+ }
|
|
+
|
|
+ for _, b := range splitIwinfoBlocks(string(out)) {
|
|
+ if ctx.Err() != nil {
|
|
+ return results
|
|
+ }
|
|
+ ssid, isAP := parseIwinfoInfo(b.text)
|
|
+ if !isAP {
|
|
+ continue
|
|
+ }
|
|
+
|
|
+ reading := system.WiFi{SSID: validSSID(ssid)}
|
|
+ if assocOut, err := exec.CommandContext(ctx, "iwinfo", b.name, "assoclist").Output(); err == nil {
|
|
+ if avg, ok := parseAssocRSSI(string(assocOut)); ok {
|
|
+ reading.Signal = &avg
|
|
+ }
|
|
+ }
|
|
+ results[b.name] = reading
|
|
+ }
|
|
+ return results
|
|
}
|
|
|
|
func collectLinux(ctx context.Context, client linuxClient) map[string]system.WiFi {
|