package plugin import ( "fmt" "sync" "github.com/shayne/hwinfo-streamdeck/internal/hwinfo" ) // Service wraps hwinfo shared mem streaming // and provides convenient methods for data access type Service struct { streamch <-chan hwinfo.Result mu sync.RWMutex sensorIDByIdx []string readingsBySensorID map[string][]hwinfo.Reading shmem *hwinfo.SharedMemory readingsBuilt bool } // Start starts the service providing updating hardware info func StartService() *Service { return &Service{ streamch: hwinfo.StreamSharedMem(), } } func (s *Service) recvShmem(shmem *hwinfo.SharedMemory) error { if shmem == nil { return fmt.Errorf("shmem nil") } s.mu.Lock() defer s.mu.Unlock() s.shmem = shmem s.sensorIDByIdx = s.sensorIDByIdx[:0] for k, v := range s.readingsBySensorID { s.readingsBySensorID[k] = v[:0] } s.readingsBuilt = false return nil } // Recv receives new hardware sensor updates func (s *Service) Recv() error { select { case r := <-s.streamch: if r.Err != nil { return r.Err } return s.recvShmem(r.Shmem) } } // Shmem provides access to underlying hwinfo shared memory func (s *Service) Shmem() (*hwinfo.SharedMemory, error) { s.mu.RLock() defer s.mu.RUnlock() if s.shmem != nil { return s.shmem, nil } return nil, fmt.Errorf("shmem nil") } // SensorIDByIdx returns ordered slice of sensor IDs func (s *Service) SensorIDByIdx() ([]string, error) { s.mu.RLock() if len(s.sensorIDByIdx) > 0 { defer s.mu.RUnlock() return s.sensorIDByIdx, nil } s.mu.RUnlock() s.mu.Lock() defer s.mu.Unlock() for sens := range s.shmem.IterSensors() { s.sensorIDByIdx = append(s.sensorIDByIdx, sens.ID()) } return s.sensorIDByIdx, nil } // ReadingsBySensorID returns slice of hwinfoReading for a given sensor ID func (s *Service) ReadingsBySensorID(id string) ([]hwinfo.Reading, error) { s.mu.RLock() if s.readingsBySensorID != nil && s.readingsBuilt { defer s.mu.RUnlock() readings, ok := s.readingsBySensorID[id] if !ok { return nil, fmt.Errorf("readings for sensor id %s do not exist", id) } return readings, nil } s.mu.RUnlock() sids, err := s.SensorIDByIdx() if err != nil { return nil, err } s.mu.Lock() defer s.mu.Unlock() if s.readingsBySensorID == nil { s.readingsBySensorID = make(map[string][]hwinfo.Reading) } for r := range s.shmem.IterReadings() { sidx := int(r.SensorIndex()) if sidx < len(sids) { sid := sids[sidx] s.readingsBySensorID[sid] = append(s.readingsBySensorID[sid], r) } else { return nil, fmt.Errorf("sensor at index %d out of range ", sidx) } } s.readingsBuilt = true readings, ok := s.readingsBySensorID[id] if !ok { return nil, fmt.Errorf("readings for sensor id %s do not exist", id) } return readings, nil }