resp→response, db→database pattern across mining, logging packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
230 lines
7.1 KiB
Go
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
|
|
})
|
|
}
|