158 lines
4.7 KiB
Go
158 lines
4.7 KiB
Go
package mining
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/adrg/xdg"
|
|
)
|
|
|
|
// minersConfigMutex protects concurrent access to miners config file operations.
|
|
var minersConfigMutex sync.RWMutex
|
|
|
|
// MinerAutostartConfig{MinerType: "xmrig", Autostart: true, Config: &config}
|
|
type MinerAutostartConfig struct {
|
|
MinerType string `json:"minerType"`
|
|
Autostart bool `json:"autostart"`
|
|
Config *Config `json:"config,omitempty"` // Store the last used config
|
|
}
|
|
|
|
// DatabaseConfig{Enabled: true, RetentionDays: 30}
|
|
type DatabaseConfig struct {
|
|
// minersConfig.Database.Enabled = false // disable hashrate persistence entirely
|
|
Enabled bool `json:"enabled"`
|
|
// minersConfig.Database.RetentionDays = 90 // purge rows older than 90 days (0 → defaults to 30)
|
|
RetentionDays int `json:"retentionDays,omitempty"`
|
|
}
|
|
|
|
// defaultDatabaseConfig() // DatabaseConfig{Enabled: true, RetentionDays: 30}
|
|
func defaultDatabaseConfig() DatabaseConfig {
|
|
return DatabaseConfig{
|
|
Enabled: true,
|
|
RetentionDays: 30,
|
|
}
|
|
}
|
|
|
|
// MinersConfig{Miners: []MinerAutostartConfig{}, Database: defaultDatabaseConfig()}
|
|
type MinersConfig struct {
|
|
Miners []MinerAutostartConfig `json:"miners"`
|
|
Database DatabaseConfig `json:"database"`
|
|
}
|
|
|
|
// minersConfigPath, err := getMinersConfigPath() // "/home/alice/.config/lethean-desktop/miners/config.json"
|
|
func getMinersConfigPath() (string, error) {
|
|
return xdg.ConfigFile("lethean-desktop/miners/config.json")
|
|
}
|
|
|
|
// minersConfig, err := LoadMinersConfig()
|
|
// if err != nil { return err }
|
|
// minersConfig.Database.Enabled = false
|
|
func LoadMinersConfig() (*MinersConfig, error) {
|
|
minersConfigMutex.RLock()
|
|
defer minersConfigMutex.RUnlock()
|
|
|
|
minersConfigPath, err := getMinersConfigPath()
|
|
if err != nil {
|
|
return nil, ErrInternal("could not determine miners config path").WithCause(err)
|
|
}
|
|
|
|
data, err := os.ReadFile(minersConfigPath)
|
|
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, ErrInternal("failed to read miners config file").WithCause(err)
|
|
}
|
|
|
|
var minersConfig MinersConfig
|
|
if err := json.Unmarshal(data, &minersConfig); err != nil {
|
|
return nil, ErrInternal("failed to unmarshal miners config").WithCause(err)
|
|
}
|
|
|
|
// Apply default database config if not set (for backwards compatibility)
|
|
if minersConfig.Database.RetentionDays == 0 {
|
|
minersConfig.Database = defaultDatabaseConfig()
|
|
}
|
|
|
|
return &minersConfig, nil
|
|
}
|
|
|
|
// minersConfig.Database.RetentionDays = 60
|
|
// if err := SaveMinersConfig(minersConfig); err != nil { return err }
|
|
func SaveMinersConfig(minersConfig *MinersConfig) error {
|
|
minersConfigMutex.Lock()
|
|
defer minersConfigMutex.Unlock()
|
|
|
|
minersConfigPath, err := getMinersConfigPath()
|
|
if err != nil {
|
|
return ErrInternal("could not determine miners config path").WithCause(err)
|
|
}
|
|
|
|
dir := filepath.Dir(minersConfigPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return ErrInternal("failed to create config directory").WithCause(err)
|
|
}
|
|
|
|
data, err := json.MarshalIndent(minersConfig, "", " ")
|
|
if err != nil {
|
|
return ErrInternal("failed to marshal miners config").WithCause(err)
|
|
}
|
|
|
|
return AtomicWriteFile(minersConfigPath, data, 0600)
|
|
}
|
|
|
|
// UpdateMinersConfig(func(minersConfig *MinersConfig) error { minersConfig.Miners = append(minersConfig.Miners, entry); return nil })
|
|
func UpdateMinersConfig(modifier func(*MinersConfig) error) error {
|
|
minersConfigMutex.Lock()
|
|
defer minersConfigMutex.Unlock()
|
|
|
|
minersConfigPath, err := getMinersConfigPath()
|
|
if err != nil {
|
|
return ErrInternal("could not determine miners config path").WithCause(err)
|
|
}
|
|
|
|
// Load current config
|
|
var minersConfig MinersConfig
|
|
data, err := os.ReadFile(minersConfigPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
minersConfig = MinersConfig{
|
|
Miners: []MinerAutostartConfig{},
|
|
Database: defaultDatabaseConfig(),
|
|
}
|
|
} else {
|
|
return ErrInternal("failed to read miners config file").WithCause(err)
|
|
}
|
|
} else {
|
|
if err := json.Unmarshal(data, &minersConfig); err != nil {
|
|
return ErrInternal("failed to unmarshal miners config").WithCause(err)
|
|
}
|
|
if minersConfig.Database.RetentionDays == 0 {
|
|
minersConfig.Database = defaultDatabaseConfig()
|
|
}
|
|
}
|
|
|
|
// Apply the modification
|
|
if err := modifier(&minersConfig); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Save atomically
|
|
dir := filepath.Dir(minersConfigPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return ErrInternal("failed to create config directory").WithCause(err)
|
|
}
|
|
|
|
newData, err := json.MarshalIndent(minersConfig, "", " ")
|
|
if err != nil {
|
|
return ErrInternal("failed to marshal miners config").WithCause(err)
|
|
}
|
|
|
|
return AtomicWriteFile(minersConfigPath, newData, 0600)
|
|
}
|