diff --git a/src/index.ts b/src/index.ts index a9b17ac..d1a7f17 100644 --- a/src/index.ts +++ b/src/index.ts @@ -239,7 +239,7 @@ export default class DownloadQueue { this.isPausedByUser = !startActive; // First revive tasks that were working in the background - existingTasks.forEach(task => this.reviveTask(task)); + await Promise.all(existingTasks.map(task => this.reviveTask(task))); // Now start downloads for specs that haven't finished const specsToDownload = this.specs.filter( @@ -731,9 +731,12 @@ export default class DownloadQueue { } } - private reviveTask(task: DownloadTask) { + private async reviveTask(task: DownloadTask) { const spec = this.specs.find(spec => spec.id === task.id); - if (spec) { + + // Don't revive finished tasks or ones that already have lazy deletes in + // progress. + if (spec && !spec.finished && spec.createTime > 0) { let shouldAddTask = true; switch (task.state) { @@ -778,6 +781,18 @@ export default class DownloadQueue { } else { if (["DOWNLOADING", "PAUSED"].includes(task.state)) { task.stop(); + + if (spec && !spec.finished) { + try { + // There might be a partially downloaded file on disk. We need to + // get rid of it in case a lazy-delete spec is revived, at which + // point an existing file on disk will be taken to be a + // successfully downloaded one. + await RNFS.unlink(spec.path); + } catch { + // Expected for missing files + } + } } } } diff --git a/test/index.spec.ts b/test/index.spec.ts index f9b30b8..4ca5654 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -439,6 +439,25 @@ describe("DownloadQueue", () => { expect(task.stop).toHaveBeenCalledTimes(2); }); + it("stops lazy-deleted tasks from previous launches", async () => { + const queue = new DownloadQueue(); + + (checkForExistingDownloads as jest.Mock).mockReturnValue([task]); + await kvfs.write("/mydomain/foo", { + id: task.id, + url: "http://foo.com/a.mp3", + path: `${RNFS.DocumentDirectoryPath}/DownloadQueue/mydomain/foo`, + createTime: -(Date.now() + 300000), // simulate lazy-delete + }); + + task.state = "DOWNLOADING"; + await queue.init({ domain: "mydomain" }); + + expect(task.stop).toHaveBeenCalledTimes(1); + // Should also delete partially-downloaded file + expect(unlink).toHaveBeenCalledTimes(1); + }); + it("starts downloads for specs without tasks or files", async () => { const queue = new DownloadQueue(); @@ -1652,7 +1671,7 @@ describe("DownloadQueue", () => { it("should handle a case where spec is finished but file is missing", async () => { const queue = new DownloadQueue(); - (download as jest.Mock).mockImplementation(_ => + (download as jest.Mock).mockImplementation(() => Object.assign(task, { done: jest.fn((handler: DoneHandler) => { task._done = handler; @@ -1676,7 +1695,7 @@ describe("DownloadQueue", () => { Platform.OS = "android"; const queue = new DownloadQueue(); - (download as jest.Mock).mockImplementation(_ => + (download as jest.Mock).mockImplementation(() => Object.assign(task, { done: jest.fn((handler: DoneHandler) => { task._done = handler;