package mining import ( "encoding/json" "fmt" "os" "path/filepath" "sync" "github.com/adrg/xdg" ) const settingsFileName = "settings.json" // WindowState stores the last window position and size type WindowState struct { X int `json:"x"` Y int `json:"y"` Width int `json:"width"` Height int `json:"height"` Maximized bool `json:"maximized"` } // MinerDefaults stores default configuration for miners 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 % } // AppSettings stores application-wide settings 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 { mu 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, fmt.Errorf("could not resolve settings path: %w", 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, fmt.Errorf("could not save default settings: %w", saveErr) } } else { return nil, fmt.Errorf("could not load settings: %w", err) } } return settingsManager, nil } // if err := settingsManager.Load(); err != nil && !os.IsNotExist(err) { return err } func (settingsManager *SettingsManager) Load() error { settingsManager.mu.Lock() defer settingsManager.mu.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.mu.Lock() defer settingsManager.mu.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.mu.RLock() defer settingsManager.mu.RUnlock() // Return a copy to prevent concurrent modification settingsCopy := *settingsManager.settings return &settingsCopy } // settingsManager.Update(func(s *AppSettings) { s.Theme = "dark" }) func (settingsManager *SettingsManager) Update(fn func(*AppSettings)) error { settingsManager.mu.Lock() defer settingsManager.mu.Unlock() fn(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(s *AppSettings) { s.Window.X = x s.Window.Y = y s.Window.Width = width s.Window.Height = height s.Window.Maximized = maximized }) } // state := settingsManager.GetWindowState() // if state.Maximized { ... } func (settingsManager *SettingsManager) GetWindowState() WindowState { settingsManager.mu.RLock() defer settingsManager.mu.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(s *AppSettings) { s.StartOnBoot = enabled }) } // if err := settingsManager.SetAutostartMiners(true); err != nil { return err } func (settingsManager *SettingsManager) SetAutostartMiners(enabled bool) error { return settingsManager.Update(func(s *AppSettings) { s.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(s *AppSettings) { s.EnableCPUThrottle = enabled if percent > 0 && percent <= 100 { s.CPUThrottlePercent = percent } }) } // settingsManager.SetMinerDefaults(MinerDefaults{DefaultPool: "pool.minexmr.com:4444", CPUMaxThreadsHint: 50}) func (settingsManager *SettingsManager) SetMinerDefaults(defaults MinerDefaults) error { return settingsManager.Update(func(s *AppSettings) { s.MinerDefaults = defaults }) }