Mining/pkg/mining/settings_manager.go
Claude 1f9624279a
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run
ax(batch): rename abbreviated variables to predictable names
resp→response, db→database pattern across mining, logging packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 04:47:58 +01:00

230 lines
7.1 KiB
Go

package mining
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"github.com/adrg/xdg"
)
const settingsFileName = "settings.json"
// state := settingsManager.GetWindowState()
// if state.Maximized { w.SetSize(state.Width, state.Height) }
type WindowState struct {
X int `json:"x"`
Y int `json:"y"`
Width int `json:"width"`
Height int `json:"height"`
Maximized bool `json:"maximized"`
}
// settingsManager.SetMinerDefaults(MinerDefaults{DefaultPool: "pool.minexmr.com:4444", CPUMaxThreadsHint: 50})
type MinerDefaults struct {
DefaultPool string `json:"defaultPool,omitempty"`
DefaultWallet string `json:"defaultWallet,omitempty"`
DefaultAlgorithm string `json:"defaultAlgorithm,omitempty"`
CPUMaxThreadsHint int `json:"cpuMaxThreadsHint,omitempty"` // Default CPU throttle percentage
CPUThrottleThreshold int `json:"cpuThrottleThreshold,omitempty"` // Throttle when CPU exceeds this %
}
// settings := settingsManager.Get()
// if settings.Theme == "dark" { applyDarkMode() }
type AppSettings struct {
// Window settings
Window WindowState `json:"window"`
// Behavior settings
StartOnBoot bool `json:"startOnBoot"`
MinimizeToTray bool `json:"minimizeToTray"`
StartMinimized bool `json:"startMinimized"`
AutostartMiners bool `json:"autostartMiners"`
ShowNotifications bool `json:"showNotifications"`
// Mining settings
MinerDefaults MinerDefaults `json:"minerDefaults"`
PauseOnBattery bool `json:"pauseOnBattery"`
PauseOnUserActive bool `json:"pauseOnUserActive"`
PauseOnUserActiveDelay int `json:"pauseOnUserActiveDelay"` // Seconds of inactivity before resuming
// Performance settings
EnableCPUThrottle bool `json:"enableCpuThrottle"`
CPUThrottlePercent int `json:"cpuThrottlePercent"` // Target max CPU % when throttling
CPUMonitorInterval int `json:"cpuMonitorInterval"` // Seconds between CPU checks
AutoThrottleOnHighTemp bool `json:"autoThrottleOnHighTemp"` // Throttle when CPU temp is high
// Theme
Theme string `json:"theme"` // "light", "dark", "system"
}
// settings := DefaultSettings()
// settings.Theme = "dark"
func DefaultSettings() *AppSettings {
return &AppSettings{
Window: WindowState{
Width: 1400,
Height: 900,
},
StartOnBoot: false,
MinimizeToTray: true,
StartMinimized: false,
AutostartMiners: false,
ShowNotifications: true,
MinerDefaults: MinerDefaults{
CPUMaxThreadsHint: 50, // Default to 50% CPU
CPUThrottleThreshold: 80, // Throttle if CPU > 80%
},
PauseOnBattery: true,
PauseOnUserActive: false,
PauseOnUserActiveDelay: 60,
EnableCPUThrottle: false,
CPUThrottlePercent: 70,
CPUMonitorInterval: 5,
AutoThrottleOnHighTemp: false,
Theme: "system",
}
}
// settingsManager, err := NewSettingsManager()
// settings := settingsManager.Get()
type SettingsManager struct {
mutex sync.RWMutex
settings *AppSettings
settingsPath string
}
// settingsManager, err := NewSettingsManager()
// if err != nil { return err }
func NewSettingsManager() (*SettingsManager, error) {
settingsPath, err := xdg.ConfigFile(filepath.Join("lethean-desktop", settingsFileName))
if err != nil {
return nil, ErrInternal("could not resolve settings path").WithCause(err)
}
settingsManager := &SettingsManager{
settings: DefaultSettings(),
settingsPath: settingsPath,
}
if err := settingsManager.Load(); err != nil {
// If file doesn't exist, use defaults and save them
if os.IsNotExist(err) {
if saveErr := settingsManager.Save(); saveErr != nil {
return nil, ErrInternal("could not save default settings").WithCause(saveErr)
}
} else {
return nil, ErrInternal("could not load settings").WithCause(err)
}
}
return settingsManager, nil
}
// if err := settingsManager.Load(); err != nil && !os.IsNotExist(err) { return err }
func (settingsManager *SettingsManager) Load() error {
settingsManager.mutex.Lock()
defer settingsManager.mutex.Unlock()
data, err := os.ReadFile(settingsManager.settingsPath)
if err != nil {
return err
}
var settings AppSettings
if err := json.Unmarshal(data, &settings); err != nil {
return err
}
settingsManager.settings = &settings
return nil
}
// if err := settingsManager.Save(); err != nil { return err }
func (settingsManager *SettingsManager) Save() error {
settingsManager.mutex.Lock()
defer settingsManager.mutex.Unlock()
data, err := json.MarshalIndent(settingsManager.settings, "", " ")
if err != nil {
return err
}
return os.WriteFile(settingsManager.settingsPath, data, 0600)
}
// settings := settingsManager.Get()
// if settings.Theme == "dark" { ... }
func (settingsManager *SettingsManager) Get() *AppSettings {
settingsManager.mutex.RLock()
defer settingsManager.mutex.RUnlock()
settingsCopy := *settingsManager.settings
return &settingsCopy
}
// settingsManager.Update(func(settings *AppSettings) { settings.Theme = "dark" })
func (settingsManager *SettingsManager) Update(modifier func(*AppSettings)) error {
settingsManager.mutex.Lock()
defer settingsManager.mutex.Unlock()
modifier(settingsManager.settings)
data, err := json.MarshalIndent(settingsManager.settings, "", " ")
if err != nil {
return err
}
return os.WriteFile(settingsManager.settingsPath, data, 0600)
}
// settingsManager.UpdateWindowState(100, 200, 1400, 900, false)
func (settingsManager *SettingsManager) UpdateWindowState(x, y, width, height int, maximized bool) error {
return settingsManager.Update(func(settings *AppSettings) {
settings.Window.X = x
settings.Window.Y = y
settings.Window.Width = width
settings.Window.Height = height
settings.Window.Maximized = maximized
})
}
// state := settingsManager.GetWindowState()
// if state.Maximized { ... }
func (settingsManager *SettingsManager) GetWindowState() WindowState {
settingsManager.mutex.RLock()
defer settingsManager.mutex.RUnlock()
return settingsManager.settings.Window
}
// if err := settingsManager.SetStartOnBoot(true); err != nil { return err }
func (settingsManager *SettingsManager) SetStartOnBoot(enabled bool) error {
return settingsManager.Update(func(settings *AppSettings) {
settings.StartOnBoot = enabled
})
}
// if err := settingsManager.SetAutostartMiners(true); err != nil { return err }
func (settingsManager *SettingsManager) SetAutostartMiners(enabled bool) error {
return settingsManager.Update(func(settings *AppSettings) {
settings.AutostartMiners = enabled
})
}
// if err := settingsManager.SetCPUThrottle(true, 70); err != nil { return err }
func (settingsManager *SettingsManager) SetCPUThrottle(enabled bool, percent int) error {
return settingsManager.Update(func(settings *AppSettings) {
settings.EnableCPUThrottle = enabled
if percent > 0 && percent <= 100 {
settings.CPUThrottlePercent = percent
}
})
}
// settingsManager.SetMinerDefaults(MinerDefaults{DefaultPool: "pool.minexmr.com:4444", CPUMaxThreadsHint: 50})
func (settingsManager *SettingsManager) SetMinerDefaults(defaults MinerDefaults) error {
return settingsManager.Update(func(settings *AppSettings) {
settings.MinerDefaults = defaults
})
}