mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-14 09:42:10 -04:00
core: refactor to use a generic-compatible syncmap
This commit is contained in:
@@ -24,7 +24,6 @@ const (
|
||||
|
||||
func NewDDCBackend() (*DDCBackend, error) {
|
||||
b := &DDCBackend{
|
||||
devices: make(map[string]*ddcDevice),
|
||||
scanInterval: 30 * time.Second,
|
||||
debounceTimers: make(map[string]*time.Timer),
|
||||
debouncePending: make(map[string]ddcPendingSet),
|
||||
@@ -53,10 +52,10 @@ func (b *DDCBackend) scanI2CDevices() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.devicesMutex.Lock()
|
||||
defer b.devicesMutex.Unlock()
|
||||
|
||||
b.devices = make(map[string]*ddcDevice)
|
||||
b.devices.Range(func(key string, value *ddcDevice) bool {
|
||||
b.devices.Delete(key)
|
||||
return true
|
||||
})
|
||||
|
||||
for i := 0; i < 32; i++ {
|
||||
busPath := fmt.Sprintf("/dev/i2c-%d", i)
|
||||
@@ -64,7 +63,6 @@ func (b *DDCBackend) scanI2CDevices() error {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip SMBus, GPU internal buses (e.g. AMDGPU SMU) to prevent GPU hangs
|
||||
if isIgnorableI2CBus(i) {
|
||||
log.Debugf("Skipping ignorable i2c-%d", i)
|
||||
continue
|
||||
@@ -77,7 +75,7 @@ func (b *DDCBackend) scanI2CDevices() error {
|
||||
|
||||
id := fmt.Sprintf("ddc:i2c-%d", i)
|
||||
dev.id = id
|
||||
b.devices[id] = dev
|
||||
b.devices.Store(id, dev)
|
||||
log.Debugf("found DDC device on i2c-%d", i)
|
||||
}
|
||||
|
||||
@@ -164,12 +162,9 @@ func (b *DDCBackend) GetDevices() ([]Device, error) {
|
||||
log.Debugf("DDC scan error: %v", err)
|
||||
}
|
||||
|
||||
b.devicesMutex.Lock()
|
||||
defer b.devicesMutex.Unlock()
|
||||
devices := make([]Device, 0)
|
||||
|
||||
devices := make([]Device, 0, len(b.devices))
|
||||
|
||||
for id, dev := range b.devices {
|
||||
b.devices.Range(func(id string, dev *ddcDevice) bool {
|
||||
devices = append(devices, Device{
|
||||
Class: ClassDDC,
|
||||
ID: id,
|
||||
@@ -179,7 +174,8 @@ func (b *DDCBackend) GetDevices() ([]Device, error) {
|
||||
CurrentPercent: dev.lastBrightness,
|
||||
Backend: "ddc",
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
@@ -189,9 +185,7 @@ func (b *DDCBackend) SetBrightness(id string, value int, exponential bool, callb
|
||||
}
|
||||
|
||||
func (b *DDCBackend) SetBrightnessWithExponent(id string, value int, exponential bool, exponent float64, callback func()) error {
|
||||
b.devicesMutex.RLock()
|
||||
_, ok := b.devices[id]
|
||||
b.devicesMutex.RUnlock()
|
||||
_, ok := b.devices.Load(id)
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("device not found: %s", id)
|
||||
@@ -202,8 +196,6 @@ func (b *DDCBackend) SetBrightnessWithExponent(id string, value int, exponential
|
||||
}
|
||||
|
||||
b.debounceMutex.Lock()
|
||||
defer b.debounceMutex.Unlock()
|
||||
|
||||
b.debouncePending[id] = ddcPendingSet{
|
||||
percent: value,
|
||||
callback: callback,
|
||||
@@ -234,14 +226,13 @@ func (b *DDCBackend) SetBrightnessWithExponent(id string, value int, exponential
|
||||
}
|
||||
})
|
||||
}
|
||||
b.debounceMutex.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *DDCBackend) setBrightnessImmediateWithExponent(id string, value int) error {
|
||||
b.devicesMutex.RLock()
|
||||
dev, ok := b.devices[id]
|
||||
b.devicesMutex.RUnlock()
|
||||
dev, ok := b.devices.Load(id)
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("device not found: %s", id)
|
||||
@@ -266,9 +257,8 @@ func (b *DDCBackend) setBrightnessImmediateWithExponent(id string, value int) er
|
||||
return fmt.Errorf("get current capability: %w", err)
|
||||
}
|
||||
max = cap.max
|
||||
b.devicesMutex.Lock()
|
||||
dev.max = max
|
||||
b.devicesMutex.Unlock()
|
||||
b.devices.Store(id, dev)
|
||||
}
|
||||
|
||||
if err := b.setVCPFeature(fd, VCP_BRIGHTNESS, value); err != nil {
|
||||
@@ -277,10 +267,9 @@ func (b *DDCBackend) setBrightnessImmediateWithExponent(id string, value int) er
|
||||
|
||||
log.Debugf("set %s to %d/%d", id, value, max)
|
||||
|
||||
b.devicesMutex.Lock()
|
||||
dev.max = max
|
||||
dev.lastBrightness = value
|
||||
b.devicesMutex.Unlock()
|
||||
b.devices.Store(id, dev)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -360,8 +360,7 @@ func (m *Manager) broadcastDeviceUpdate(deviceID string) {
|
||||
|
||||
log.Debugf("Broadcasting device update: %s at %d%%", deviceID, targetDevice.CurrentPercent)
|
||||
|
||||
m.updateSubscribers.Range(func(key, value interface{}) bool {
|
||||
ch := value.(chan DeviceUpdate)
|
||||
m.updateSubscribers.Range(func(key string, ch chan DeviceUpdate) bool {
|
||||
select {
|
||||
case ch <- update:
|
||||
default:
|
||||
|
||||
@@ -13,9 +13,8 @@ import (
|
||||
|
||||
func NewSysfsBackend() (*SysfsBackend, error) {
|
||||
b := &SysfsBackend{
|
||||
basePath: "/sys/class",
|
||||
classes: []string{"backlight", "leds"},
|
||||
deviceCache: make(map[string]*sysfsDevice),
|
||||
basePath: "/sys/class",
|
||||
classes: []string{"backlight", "leds"},
|
||||
}
|
||||
|
||||
if err := b.scanDevices(); err != nil {
|
||||
@@ -26,9 +25,6 @@ func NewSysfsBackend() (*SysfsBackend, error) {
|
||||
}
|
||||
|
||||
func (b *SysfsBackend) scanDevices() error {
|
||||
b.deviceCacheMutex.Lock()
|
||||
defer b.deviceCacheMutex.Unlock()
|
||||
|
||||
for _, class := range b.classes {
|
||||
classPath := filepath.Join(b.basePath, class)
|
||||
entries, err := os.ReadDir(classPath)
|
||||
@@ -68,13 +64,13 @@ func (b *SysfsBackend) scanDevices() error {
|
||||
}
|
||||
|
||||
deviceID := fmt.Sprintf("%s:%s", class, entry.Name())
|
||||
b.deviceCache[deviceID] = &sysfsDevice{
|
||||
b.deviceCache.Store(deviceID, &sysfsDevice{
|
||||
class: deviceClass,
|
||||
id: deviceID,
|
||||
name: entry.Name(),
|
||||
maxBrightness: maxBrightness,
|
||||
minValue: minValue,
|
||||
}
|
||||
})
|
||||
|
||||
log.Debugf("found %s device: %s (max=%d)", class, entry.Name(), maxBrightness)
|
||||
}
|
||||
@@ -106,19 +102,16 @@ func shouldSuppressDevice(name string) bool {
|
||||
}
|
||||
|
||||
func (b *SysfsBackend) GetDevices() ([]Device, error) {
|
||||
b.deviceCacheMutex.RLock()
|
||||
defer b.deviceCacheMutex.RUnlock()
|
||||
devices := make([]Device, 0)
|
||||
|
||||
devices := make([]Device, 0, len(b.deviceCache))
|
||||
|
||||
for _, dev := range b.deviceCache {
|
||||
b.deviceCache.Range(func(key string, dev *sysfsDevice) bool {
|
||||
if shouldSuppressDevice(dev.name) {
|
||||
continue
|
||||
return true
|
||||
}
|
||||
|
||||
parts := strings.SplitN(dev.id, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
return true
|
||||
}
|
||||
|
||||
class := parts[0]
|
||||
@@ -130,13 +123,13 @@ func (b *SysfsBackend) GetDevices() ([]Device, error) {
|
||||
brightnessData, err := os.ReadFile(brightnessPath)
|
||||
if err != nil {
|
||||
log.Debugf("failed to read brightness for %s: %v", dev.id, err)
|
||||
continue
|
||||
return true
|
||||
}
|
||||
|
||||
current, err := strconv.Atoi(strings.TrimSpace(string(brightnessData)))
|
||||
if err != nil {
|
||||
log.Debugf("failed to parse brightness for %s: %v", dev.id, err)
|
||||
continue
|
||||
return true
|
||||
}
|
||||
|
||||
percent := b.ValueToPercent(current, dev, false)
|
||||
@@ -150,16 +143,14 @@ func (b *SysfsBackend) GetDevices() ([]Device, error) {
|
||||
CurrentPercent: percent,
|
||||
Backend: "sysfs",
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
func (b *SysfsBackend) GetDevice(id string) (*sysfsDevice, error) {
|
||||
b.deviceCacheMutex.RLock()
|
||||
defer b.deviceCacheMutex.RUnlock()
|
||||
|
||||
dev, ok := b.deviceCache[id]
|
||||
dev, ok := b.deviceCache.Load(id)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("device not found: %s", id)
|
||||
}
|
||||
|
||||
@@ -31,9 +31,8 @@ func TestManager_SetBrightness_LogindSuccess(t *testing.T) {
|
||||
mockLogind := NewLogindBackendWithConn(mockConn)
|
||||
|
||||
sysfs := &SysfsBackend{
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight"},
|
||||
deviceCache: make(map[string]*sysfsDevice),
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight"},
|
||||
}
|
||||
|
||||
if err := sysfs.scanDevices(); err != nil {
|
||||
@@ -103,9 +102,8 @@ func TestManager_SetBrightness_LogindFailsFallbackToSysfs(t *testing.T) {
|
||||
mockLogind := NewLogindBackendWithConn(mockConn)
|
||||
|
||||
sysfs := &SysfsBackend{
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight"},
|
||||
deviceCache: make(map[string]*sysfsDevice),
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight"},
|
||||
}
|
||||
|
||||
if err := sysfs.scanDevices(); err != nil {
|
||||
@@ -171,9 +169,8 @@ func TestManager_SetBrightness_NoLogind(t *testing.T) {
|
||||
}
|
||||
|
||||
sysfs := &SysfsBackend{
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight"},
|
||||
deviceCache: make(map[string]*sysfsDevice),
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight"},
|
||||
}
|
||||
|
||||
if err := sysfs.scanDevices(); err != nil {
|
||||
@@ -234,9 +231,8 @@ func TestManager_SetBrightness_LEDWithLogind(t *testing.T) {
|
||||
mockLogind := NewLogindBackendWithConn(mockConn)
|
||||
|
||||
sysfs := &SysfsBackend{
|
||||
basePath: tmpDir,
|
||||
classes: []string{"leds"},
|
||||
deviceCache: make(map[string]*sysfsDevice),
|
||||
basePath: tmpDir,
|
||||
classes: []string{"leds"},
|
||||
}
|
||||
|
||||
if err := sysfs.scanDevices(); err != nil {
|
||||
|
||||
@@ -160,26 +160,21 @@ func TestSysfsBackend_ScanDevices(t *testing.T) {
|
||||
}
|
||||
|
||||
b := &SysfsBackend{
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight", "leds"},
|
||||
deviceCache: make(map[string]*sysfsDevice),
|
||||
basePath: tmpDir,
|
||||
classes: []string{"backlight", "leds"},
|
||||
}
|
||||
|
||||
if err := b.scanDevices(); err != nil {
|
||||
t.Fatalf("scanDevices() error = %v", err)
|
||||
}
|
||||
|
||||
if len(b.deviceCache) != 2 {
|
||||
t.Errorf("expected 2 devices, got %d", len(b.deviceCache))
|
||||
}
|
||||
|
||||
backlightID := "backlight:test_backlight"
|
||||
if _, ok := b.deviceCache[backlightID]; !ok {
|
||||
if _, ok := b.deviceCache.Load(backlightID); !ok {
|
||||
t.Errorf("backlight device not found")
|
||||
}
|
||||
|
||||
ledID := "leds:test_led"
|
||||
if _, ok := b.deviceCache[ledID]; !ok {
|
||||
if _, ok := b.deviceCache.Load(ledID); !ok {
|
||||
t.Errorf("LED device not found")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package brightness
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
|
||||
)
|
||||
|
||||
type DeviceClass string
|
||||
@@ -51,8 +53,8 @@ type Manager struct {
|
||||
stateMutex sync.RWMutex
|
||||
state State
|
||||
|
||||
subscribers sync.Map
|
||||
updateSubscribers sync.Map
|
||||
subscribers syncmap.Map[string, chan State]
|
||||
updateSubscribers syncmap.Map[string, chan DeviceUpdate]
|
||||
|
||||
broadcastMutex sync.Mutex
|
||||
broadcastTimer *time.Timer
|
||||
@@ -66,8 +68,7 @@ type SysfsBackend struct {
|
||||
basePath string
|
||||
classes []string
|
||||
|
||||
deviceCache map[string]*sysfsDevice
|
||||
deviceCacheMutex sync.RWMutex
|
||||
deviceCache syncmap.Map[string, *sysfsDevice]
|
||||
}
|
||||
|
||||
type sysfsDevice struct {
|
||||
@@ -79,8 +80,7 @@ type sysfsDevice struct {
|
||||
}
|
||||
|
||||
type DDCBackend struct {
|
||||
devices map[string]*ddcDevice
|
||||
devicesMutex sync.RWMutex
|
||||
devices syncmap.Map[string, *ddcDevice]
|
||||
|
||||
scanMutex sync.Mutex
|
||||
lastScan time.Time
|
||||
@@ -129,7 +129,7 @@ func (m *Manager) Subscribe(id string) chan State {
|
||||
func (m *Manager) Unsubscribe(id string) {
|
||||
|
||||
if val, ok := m.subscribers.LoadAndDelete(id); ok {
|
||||
close(val.(chan State))
|
||||
close(val)
|
||||
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (m *Manager) SubscribeUpdates(id string) chan DeviceUpdate {
|
||||
|
||||
func (m *Manager) UnsubscribeUpdates(id string) {
|
||||
if val, ok := m.updateSubscribers.LoadAndDelete(id); ok {
|
||||
close(val.(chan DeviceUpdate))
|
||||
close(val)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,8 +152,7 @@ func (m *Manager) NotifySubscribers() {
|
||||
state := m.state
|
||||
m.stateMutex.RUnlock()
|
||||
|
||||
m.subscribers.Range(func(key, value interface{}) bool {
|
||||
ch := value.(chan State)
|
||||
m.subscribers.Range(func(key string, ch chan State) bool {
|
||||
select {
|
||||
case ch <- state:
|
||||
default:
|
||||
@@ -171,14 +170,12 @@ func (m *Manager) GetState() State {
|
||||
func (m *Manager) Close() {
|
||||
close(m.stopChan)
|
||||
|
||||
m.subscribers.Range(func(key, value interface{}) bool {
|
||||
ch := value.(chan State)
|
||||
m.subscribers.Range(func(key string, ch chan State) bool {
|
||||
close(ch)
|
||||
m.subscribers.Delete(key)
|
||||
return true
|
||||
})
|
||||
m.updateSubscribers.Range(func(key, value interface{}) bool {
|
||||
ch := value.(chan DeviceUpdate)
|
||||
m.updateSubscribers.Range(func(key string, ch chan DeviceUpdate) bool {
|
||||
close(ch)
|
||||
m.updateSubscribers.Delete(key)
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user