mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 00:56:16 +00:00
replace copy-and-delete migration with atomic MoveDevice
This commit is contained in:
committed by
Tobias Gesellchen
parent
7a268a0372
commit
65b142881a
@@ -1647,6 +1647,24 @@ func (ds *DataStore) RemoveDeviceDir(account, device string) error {
|
||||
return ds.RemoveDevice(account, device)
|
||||
}
|
||||
|
||||
// MoveDevice atomically moves a device directory from one account to another
|
||||
// on the same filesystem. If the target account directory doesn't exist it is
|
||||
// created. Returns an error if the rename fails (leaving the source intact).
|
||||
func (ds *DataStore) MoveDevice(oldAccount, newAccount, deviceID string) error {
|
||||
ds.fileMutex.Lock()
|
||||
defer ds.fileMutex.Unlock()
|
||||
|
||||
oldDir := ds.AccountDeviceDir(oldAccount, deviceID)
|
||||
newDir := ds.AccountDeviceDir(newAccount, deviceID)
|
||||
|
||||
newAccountDir := filepath.Dir(newDir)
|
||||
if err := ds.rootMkdirAll(newAccountDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ds.rootRename(oldDir, newDir)
|
||||
}
|
||||
|
||||
// DeduceSourceIDs updates the source IDs in the given slice by deducing them from recents and presets.
|
||||
func (ds *DataStore) DeduceSourceIDs(account, device string, sources []models.ConfiguredSource) {
|
||||
// Deduce source IDs from recents and presets
|
||||
|
||||
@@ -457,3 +457,40 @@ func TestSettingsPersistence(t *testing.T) {
|
||||
t.Errorf("Expected DiscoveryEnabled %v, got %v", settings.DiscoveryEnabled, loaded.DiscoveryEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoveDeviceMigratesData(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
ds := NewDataStore(tempDir)
|
||||
|
||||
oldAccount := "default"
|
||||
newAccount := "8637922"
|
||||
deviceID := "F4E11E930BEB"
|
||||
|
||||
// Seed the device under the old account with presets
|
||||
presets := []models.ServicePreset{
|
||||
{ID: "1", ServiceContentItem: models.ServiceContentItem{Name: "Radio Preset", ContentItemType: "stationurl"}},
|
||||
}
|
||||
if err := ds.SavePresets(oldAccount, deviceID, presets); err != nil {
|
||||
t.Fatalf("SavePresets under %s: %v", oldAccount, err)
|
||||
}
|
||||
|
||||
// Move the device to the new account
|
||||
if err := ds.MoveDevice(oldAccount, newAccount, deviceID); err != nil {
|
||||
t.Fatalf("MoveDevice %s → %s: %v", oldAccount, newAccount, err)
|
||||
}
|
||||
|
||||
// Verify presets survived the move under the new account
|
||||
moved, err := ds.GetPresets(newAccount, deviceID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetPresets under %s after move: %v", newAccount, err)
|
||||
}
|
||||
if len(moved) != 1 || moved[0].Name != "Radio Preset" {
|
||||
t.Errorf("presets not preserved: got %+v", moved)
|
||||
}
|
||||
|
||||
// Verify the old account no longer has the device
|
||||
oldPresets, err := ds.GetPresets(oldAccount, deviceID)
|
||||
if err == nil && len(oldPresets) > 0 {
|
||||
t.Errorf("old account %s still has presets after move: %+v", oldAccount, oldPresets)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,19 +1058,12 @@ func (s *Server) handleDiscoveredDevice(d models.DiscoveredDevice) {
|
||||
}
|
||||
|
||||
// If the speaker reports a paired account that differs from the stored
|
||||
// location, clean up the stale entry so ListAllDevices doesn't return duplicates.
|
||||
// location, migrate the device directory so ListAllDevices doesn't return duplicates.
|
||||
if liveInfo.MargeAccountUUID != "" && storedAccount != "" && liveInfo.MargeAccountUUID != storedAccount {
|
||||
// Preserve presets, recents and sources before cleaning up
|
||||
if presets, err := s.ds.GetPresets(storedAccount, deviceID); err == nil && len(presets) > 0 {
|
||||
_ = s.ds.SavePresets(liveInfo.MargeAccountUUID, deviceID, presets)
|
||||
if err := s.ds.MoveDevice(storedAccount, accountID, deviceID); err != nil {
|
||||
log.Printf("Failed to migrate device %s from %s to %s: %v",
|
||||
deviceID, storedAccount, accountID, err)
|
||||
}
|
||||
if recents, err := s.ds.GetRecents(storedAccount, deviceID); err == nil && len(recents) > 0 {
|
||||
_ = s.ds.SaveRecents(liveInfo.MargeAccountUUID, deviceID, recents)
|
||||
}
|
||||
if sources, err := s.ds.GetConfiguredSources(storedAccount, deviceID); err == nil && len(sources) > 0 {
|
||||
_ = s.ds.SaveConfiguredSources(liveInfo.MargeAccountUUID, deviceID, sources)
|
||||
}
|
||||
s.ds.RemoveDevice(storedAccount, deviceID)
|
||||
}
|
||||
|
||||
// 4. Get primary MAC address from networkInfo
|
||||
|
||||
Reference in New Issue
Block a user