Mining/pkg/mining/profile_manager.go
Virgil 6838f26d99
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run
Improve AX naming and path docs
2026-04-04 05:17:54 +00:00

168 lines
4.8 KiB
Go

package mining
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"github.com/adrg/xdg"
"github.com/google/uuid"
)
const profileConfigFileName = "mining_profiles.json"
var profileConfigRelativePath = filepath.Join("lethean-desktop", profileConfigFileName)
// profileManager, err := NewProfileManager()
// profileManager.CreateProfile(&MiningProfile{Name: "XMRig CPU", MinerType: "xmrig"})
type ProfileManager struct {
mutex sync.RWMutex
profiles map[string]*MiningProfile
configPath string
}
// profileManager, err := NewProfileManager()
// if err != nil { return err }
func NewProfileManager() (*ProfileManager, error) {
configPath, err := xdg.ConfigFile(profileConfigRelativePath)
if err != nil {
return nil, ErrInternal("could not resolve config path").WithCause(err)
}
profileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: configPath,
}
if err := profileManager.loadProfiles(); err != nil {
// If the file doesn't exist, that's fine, but any other error is a problem.
if !os.IsNotExist(err) {
return nil, ErrInternal("could not load profiles").WithCause(err)
}
}
return profileManager, nil
}
// profileManager.loadProfiles() // call after acquiring profileManager.mutex.Lock() if needed externally
func (profileManager *ProfileManager) loadProfiles() error {
profileManager.mutex.Lock()
defer profileManager.mutex.Unlock()
data, err := os.ReadFile(profileManager.configPath)
if err != nil {
return err
}
var profiles []*MiningProfile
if err := json.Unmarshal(data, &profiles); err != nil {
return err
}
profileManager.profiles = make(map[string]*MiningProfile)
for _, profile := range profiles {
profileManager.profiles[profile.ID] = profile
}
return nil
}
// profileManager.saveProfiles() // saves `lethean-desktop/mining_profiles.json` after profile changes.
func (profileManager *ProfileManager) saveProfiles() error {
profileEntries := make([]*MiningProfile, 0, len(profileManager.profiles))
for _, profile := range profileManager.profiles {
profileEntries = append(profileEntries, profile)
}
data, err := json.MarshalIndent(profileEntries, "", " ")
if err != nil {
return err
}
return AtomicWriteFile(profileManager.configPath, data, 0600)
}
// created, err := profileManager.CreateProfile(&MiningProfile{Name: "XMRig CPU", MinerType: "xmrig"})
func (profileManager *ProfileManager) CreateProfile(profile *MiningProfile) (*MiningProfile, error) {
profileManager.mutex.Lock()
defer profileManager.mutex.Unlock()
profile.ID = uuid.New().String()
profileManager.profiles[profile.ID] = profile
if err := profileManager.saveProfiles(); err != nil {
// Rollback
delete(profileManager.profiles, profile.ID)
return nil, err
}
return profile, nil
}
// profile, ok := profileManager.GetProfile("abc-123")
// if !ok { return core.E("profile.Get", "profile not found", nil) }
func (profileManager *ProfileManager) GetProfile(id string) (*MiningProfile, bool) {
profileManager.mutex.RLock()
defer profileManager.mutex.RUnlock()
profile, exists := profileManager.profiles[id]
return profile, exists
}
// profiles := profileManager.GetAllProfiles()
// for _, profile := range profiles { render(profile) }
func (profileManager *ProfileManager) GetAllProfiles() []*MiningProfile {
profileManager.mutex.RLock()
defer profileManager.mutex.RUnlock()
profileList := make([]*MiningProfile, 0, len(profileManager.profiles))
for _, profile := range profileManager.profiles {
profileList = append(profileList, profile)
}
return profileList
}
// profile.Name = "XMRig GPU"
// if err := profileManager.UpdateProfile(profile); err != nil { return err }
func (profileManager *ProfileManager) UpdateProfile(profile *MiningProfile) error {
profileManager.mutex.Lock()
defer profileManager.mutex.Unlock()
oldProfile, exists := profileManager.profiles[profile.ID]
if !exists {
return ErrProfileNotFound(profile.ID)
}
// Update in-memory state
profileManager.profiles[profile.ID] = profile
// Save to disk - rollback if save fails
if err := profileManager.saveProfiles(); err != nil {
// Restore old profile on save failure
profileManager.profiles[profile.ID] = oldProfile
return ErrInternal("failed to save profile").WithCause(err)
}
return nil
}
// if err := profileManager.DeleteProfile("abc-123"); err != nil { return err }
func (profileManager *ProfileManager) DeleteProfile(id string) error {
profileManager.mutex.Lock()
defer profileManager.mutex.Unlock()
profile, exists := profileManager.profiles[id]
if !exists {
return ErrProfileNotFound(id)
}
delete(profileManager.profiles, id)
// Save to disk - rollback if save fails
if err := profileManager.saveProfiles(); err != nil {
// Restore profile on save failure
profileManager.profiles[id] = profile
return ErrInternal("failed to delete profile").WithCause(err)
}
return nil
}