package mining import ( "encoding/json" "fmt" "os" "path/filepath" "sync" "github.com/adrg/xdg" "github.com/google/uuid" ) const profileConfigFileName = "mining_profiles.json" // profileManager, err := NewProfileManager() // profileManager.CreateProfile(profile) 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(filepath.Join("lethean-desktop", profileConfigFileName)) if err != nil { return nil, fmt.Errorf("could not resolve config path: %w", 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, fmt.Errorf("could not load profiles: %w", 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() // caller must hold profileManager.mutex before calling; uses atomic write (temp→sync→rename) func (profileManager *ProfileManager) saveProfiles() error { profileList := make([]*MiningProfile, 0, len(profileManager.profiles)) for _, profile := range profileManager.profiles { profileList = append(profileList, profile) } data, err := json.MarshalIndent(profileList, "", " ") 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 fmt.Errorf("profile with ID %s not found", 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 fmt.Errorf("failed to save profile: %w", 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 fmt.Errorf("profile with ID %s not found", 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 fmt.Errorf("failed to delete profile: %w", err) } return nil }