fix(database): handle cross-drive desktop DB migration

close #1022
This commit is contained in:
edde746
2026-05-12 10:41:32 +02:00
parent 606627cd0c
commit bae127e459
3 changed files with 166 additions and 6 deletions
+54 -5
View File
@@ -570,11 +570,7 @@ LazyDatabase _openConnection() {
// Migrate from old location on desktop (was in Documents subfolder)
if (!Platform.isAndroid && !Platform.isIOS && !await file.exists()) {
final oldFolder = await getApplicationDocumentsDirectory();
final oldFile = File(p.join(oldFolder.path, 'plezy_downloads.db'));
if (await oldFile.exists()) {
await oldFile.rename(file.path);
}
await migrateLegacyDesktopDatabase(target: file);
}
return NativeDatabase.createInBackground(
@@ -589,3 +585,56 @@ LazyDatabase _openConnection() {
);
});
}
/// Move the legacy desktop DB from `Documents/` to `ApplicationSupport/`.
/// `File.rename` only works within a single volume — Windows users with
/// OneDrive-redirected Documents (or any cross-drive setup) hit
/// `ERROR_NOT_SAME_DEVICE` (errno 17), and the uncaught throw used to
/// strand the splash on "Loading servers..." forever (#1022). Falls back
/// to copy + delete on any [FileSystemException] and swallows all errors
/// so a failed migration never propagates fatally.
///
/// [sourceOverride] and [renameOverride] are test seams — production
/// callers leave them null.
Future<void> migrateLegacyDesktopDatabase({
required File target,
File? sourceOverride,
Future<void> Function(File source, String targetPath)? renameOverride,
}) async {
final File oldFile;
if (sourceOverride != null) {
oldFile = sourceOverride;
} else {
final oldFolder = await getApplicationDocumentsDirectory();
oldFile = File(p.join(oldFolder.path, 'plezy_downloads.db'));
}
if (!await oldFile.exists()) return;
try {
if (renameOverride != null) {
await renameOverride(oldFile, target.path);
} else {
await oldFile.rename(target.path);
}
appLogger.i('Moved legacy DB from ${oldFile.path}${target.path}');
return;
} on FileSystemException catch (e) {
appLogger.w('Legacy DB rename failed (osError=${e.osError?.errorCode}); falling back to copy', error: e);
}
try {
await oldFile.copy(target.path);
try {
await oldFile.delete();
} catch (e) {
// Leaving the source behind is non-fatal — the new file is canonical.
appLogger.w('Legacy DB copied but old file delete failed: $e');
}
appLogger.i('Copied legacy DB from ${oldFile.path}${target.path}');
} catch (e, st) {
// Copy itself failed (disk full, source locked by OneDrive sync,
// permissions). Leave both files alone — drift will create a fresh
// empty DB at the new location, and a future relaunch can retry.
appLogger.e('Legacy DB migration failed entirely', error: e, stackTrace: st);
}
}