fix(torrents): harden removal reservation recovery

This commit is contained in:
NimBold
2026-08-03 03:56:15 +03:30
parent 32034e90b3
commit 79c0e48c43
11 changed files with 508 additions and 216 deletions
+22
View File
@@ -913,12 +913,18 @@ export const useDownloadStore = create<DownloadState>((set, get) => {
const normalizedUpdates = updates.fileName === undefined
? updates
: { ...updates, fileName: canonicalizeDownloadFileName(updates.fileName) };
const disablingTorrentRemoval = item.isTorrent === true
&& normalizedUpdates.torrentRemoveUnselectedFile === false
&& item.torrentRemoveUnselectedFile !== false;
if (item.status === 'downloading' || item.status === 'processing' || item.status === 'seeding' || item.status === 'retrying') {
throw new Error(i18n.t($ => $.downloadTable.transferActive));
}
if (item.status === 'ready' || item.status === 'staged' || item.status === 'completed' || item.status === 'failed') {
if (disablingTorrentRemoval) {
await invoke('clear_torrent_removal_paths', { id });
}
state.updateDownload(id, normalizedUpdates);
return;
}
@@ -932,6 +938,9 @@ export const useDownloadStore = create<DownloadState>((set, get) => {
state.unregisterBackendIds([id]);
set(current => ({ pendingOrder: current.pendingOrder.filter(value => value !== id) }));
}
if (disablingTorrentRemoval) {
await invoke('clear_torrent_removal_paths', { id });
}
state.updateDownload(id, normalizedUpdates);
if (isRegistered || wasDispatching) {
const dispatched = await dispatchItemInternal(id);
@@ -951,6 +960,9 @@ export const useDownloadStore = create<DownloadState>((set, get) => {
}
state.unregisterBackendIds([id]);
}
if (disablingTorrentRemoval) {
await invoke('clear_torrent_removal_paths', { id });
}
state.updateDownload(id, normalizedUpdates);
}
};
@@ -2386,6 +2398,16 @@ export const useDownloadStore = create<DownloadState>((set, get) => {
: state.downloads
}));
// A process can die after Aria2 has removed the unselected files but
// before the terminal event clears Firelink's reservation. Reclaim
// only the conservative terminal cases in the backend before queued
// downloads are allowed to claim paths on startup.
try {
await invoke('reconcile_torrent_removal_reservations');
} catch (error) {
console.warn('Could not reconcile Torrent removal reservations during startup:', error);
}
// The backend dispatcher is live before the frontend finishes startup.
// Synchronize the normalized queue policy before any saved download is
// allowed to claim a permit.