package mining import ( "encoding/json" "fmt" "os" "path/filepath" "sync" "github.com/adrg/xdg" ) // configMu protects concurrent access to config file operations var configMu sync.RWMutex // MinerAutostartConfig represents the configuration for a single miner's autostart settings. type MinerAutostartConfig struct { MinerType string `json:"minerType"` Autostart bool `json:"autostart"` Config *Config `json:"config,omitempty"` // Store the last used config } // DatabaseConfig holds configuration for SQLite database persistence. type DatabaseConfig struct { // Enabled determines if database persistence is active (default: true) Enabled bool `json:"enabled"` // RetentionDays is how long to keep historical data (default: 30) RetentionDays int `json:"retentionDays,omitempty"` } // defaultDatabaseConfig returns the default database configuration. func defaultDatabaseConfig() DatabaseConfig { return DatabaseConfig{ Enabled: true, RetentionDays: 30, } } // MinersConfig represents the overall configuration for all miners, including autostart settings. type MinersConfig struct { Miners []MinerAutostartConfig `json:"miners"` Database DatabaseConfig `json:"database"` } // getMinersConfigPath returns the path to the miners configuration file. func getMinersConfigPath() (string, error) { return xdg.ConfigFile("lethean-desktop/miners/config.json") } // cfg, err := LoadMinersConfig() // if err != nil { return err } // cfg.Database.Enabled = false func LoadMinersConfig() (*MinersConfig, error) { configMu.RLock() defer configMu.RUnlock() configPath, err := getMinersConfigPath() if err != nil { return nil, fmt.Errorf("could not determine miners config path: %w", err) } data, err := os.ReadFile(configPath) if err != nil { if os.IsNotExist(err) { // Return empty config with defaults if file doesn't exist return &MinersConfig{ Miners: []MinerAutostartConfig{}, Database: defaultDatabaseConfig(), }, nil } return nil, fmt.Errorf("failed to read miners config file: %w", err) } var configuration MinersConfig if err := json.Unmarshal(data, &configuration); err != nil { return nil, fmt.Errorf("failed to unmarshal miners config: %w", err) } // Apply default database config if not set (for backwards compatibility) if configuration.Database.RetentionDays == 0 { configuration.Database = defaultDatabaseConfig() } return &configuration, nil } // cfg.Database.RetentionDays = 60 // if err := SaveMinersConfig(cfg); err != nil { return err } func SaveMinersConfig(configuration *MinersConfig) error { configMu.Lock() defer configMu.Unlock() configPath, err := getMinersConfigPath() if err != nil { return fmt.Errorf("could not determine miners config path: %w", err) } dir := filepath.Dir(configPath) if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("failed to create config directory: %w", err) } data, err := json.MarshalIndent(configuration, "", " ") if err != nil { return fmt.Errorf("failed to marshal miners config: %w", err) } return AtomicWriteFile(configPath, data, 0600) } // UpdateMinersConfig atomically loads, modifies, and saves the miners config. // UpdateMinersConfig(func(c *MinersConfig) error { c.Miners = append(c.Miners, entry); return nil }) func UpdateMinersConfig(modifier func(*MinersConfig) error) error { configMu.Lock() defer configMu.Unlock() configPath, err := getMinersConfigPath() if err != nil { return fmt.Errorf("could not determine miners config path: %w", err) } // Load current config var configuration MinersConfig data, err := os.ReadFile(configPath) if err != nil { if os.IsNotExist(err) { configuration = MinersConfig{ Miners: []MinerAutostartConfig{}, Database: defaultDatabaseConfig(), } } else { return fmt.Errorf("failed to read miners config file: %w", err) } } else { if err := json.Unmarshal(data, &configuration); err != nil { return fmt.Errorf("failed to unmarshal miners config: %w", err) } if configuration.Database.RetentionDays == 0 { configuration.Database = defaultDatabaseConfig() } } // Apply the modification if err := modifier(&configuration); err != nil { return err } // Save atomically dir := filepath.Dir(configPath) if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("failed to create config directory: %w", err) } newData, err := json.MarshalIndent(configuration, "", " ") if err != nil { return fmt.Errorf("failed to marshal miners config: %w", err) } return AtomicWriteFile(configPath, newData, 0600) }