package collector import ( "context" "fmt" "log" "time" "gitea.sinav-lab.com/sinav/keenetic-exporter-v2/internal/device" "gitea.sinav-lab.com/sinav/keenetic-exporter-v2/internal/keenetic" "gitea.sinav-lab.com/sinav/keenetic-exporter-v2/internal/utils" "github.com/prometheus/client_golang/prometheus" ) type HotspotCollector struct { registeredDesc *prometheus.Desc rxBytesDesc *prometheus.Desc txBytesDesc *prometheus.Desc txRateDesc *prometheus.Desc rssiDesc *prometheus.Desc uptimeDesc *prometheus.Desc } func NewHotspotCollector() *HotspotCollector { labels := []string{"device", "mac", "ip", "client", "ssid"} return &HotspotCollector{ registeredDesc: prometheus.NewDesc("keenetic_hotspot_client_registered", "Whether the client is registered", labels, nil), rxBytesDesc: prometheus.NewDesc("keenetic_hotspot_client_rxbytes", "Total number of bytes received by the client", labels, nil), txBytesDesc: prometheus.NewDesc("keenetic_hotspot_client_txbytes", "Total number of bytes transmitted by the client", labels, nil), txRateDesc: prometheus.NewDesc("keenetic_hotspot_client_txrate", "Current transmit rate", labels, nil), rssiDesc: prometheus.NewDesc("keenetic_hotspot_client_rssi", "Received signal strength indicator (RSSI) in dBm", labels, nil), uptimeDesc: prometheus.NewDesc("keenetic_hotspot_client_uptime", "Uptime of the client device in seconds", labels, nil), } } func (c *HotspotCollector) Name() string { return "hotspot" } func (c *HotspotCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.registeredDesc ch <- c.rxBytesDesc ch <- c.txBytesDesc ch <- c.txRateDesc ch <- c.rssiDesc ch <- c.uptimeDesc } func (c *HotspotCollector) Collect(dev *device.Device, ch chan<- prometheus.Metric) error { var hotspotInfo any var ok bool hostname := dev.Name client := dev.Client dev.CacheMutex.RLock() hotspotInfo, ok = dev.Cache["hotspot"] dev.CacheMutex.RUnlock() if !ok { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) fresh, err := client.GetHotspotClientInfo(ctx) cancel() if err != nil { log.Printf("failed to get hotspot client info from %s: %v", hostname, err) return err } hotspotInfo = fresh dev.CacheMutex.Lock() dev.Cache["hotspot"] = fresh dev.CacheMutex.Unlock() } data, ok := hotspotInfo.([]*keenetic.HotspotClientInfo) if !ok { log.Printf("invalid cache data type for hotspot info on %s", hostname) return fmt.Errorf("invalid cache data type for hotspot info") } for _, hotspotClient := range data { labels := []string{hostname, hotspotClient.MAC, hotspotClient.IP, hotspotClient.Name, hotspotClient.SSID} ch <- prometheus.MustNewConstMetric(c.registeredDesc, prometheus.GaugeValue, utils.BoolToFloat(hotspotClient.Registered), labels...) ch <- prometheus.MustNewConstMetric(c.rxBytesDesc, prometheus.CounterValue, hotspotClient.RXBytes, labels...) ch <- prometheus.MustNewConstMetric(c.txBytesDesc, prometheus.CounterValue, hotspotClient.TXBytes, labels...) ch <- prometheus.MustNewConstMetric(c.txRateDesc, prometheus.GaugeValue, hotspotClient.TXRate, labels...) ch <- prometheus.MustNewConstMetric(c.rssiDesc, prometheus.GaugeValue, hotspotClient.RSSI, labels...) ch <- prometheus.MustNewConstMetric(c.uptimeDesc, prometheus.GaugeValue, hotspotClient.Uptime, labels...) } return nil }