Skip to content

Commit ae7e055

Browse files
authored
fix: don't pause downloads until ready (#42)
kesha-antonov/react-native-background-downloader#23 is a bug where pause() isn't respected by that library if you call it right after starting a download(). So instead, we pause only upon begin() or progress(). This isn't ideal, because you could start download some bytes, even if !startActive, between when you start/revive a task and when you're next able to pause it... but this is an external bug we can't control.
1 parent 9b94e51 commit ae7e055

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed

src/index.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,9 +659,14 @@ export default class DownloadQueue {
659659
});
660660

661661
this.addTask(spec.url, task);
662-
if (!this.active) {
663-
task.pause();
664-
}
662+
663+
// Bug: https://github.com/kesha-antonov/react-native-background-downloader/issues/23
664+
// This is the ideal place to pause, but the downloader has a bug that
665+
// doesn't respect that. So we defer the pause() until begin() or progress()
666+
//
667+
// if (!this.active) {
668+
// task.pause();
669+
// }
665670
}
666671

667672
/**
@@ -694,9 +699,23 @@ export default class DownloadQueue {
694699
private addTask(url: string, task: DownloadTask) {
695700
task
696701
.begin(data => {
702+
// Bug: https://github.com/kesha-antonov/react-native-background-downloader/issues/23
703+
// Basically the downloader doesn't respect the pause() if we call it
704+
// right after download(). So we end up having to pause only after the
705+
// download sends us this begin() callback. When #23 is fixed, we can
706+
// in theory move this into the end of start(), after download().
707+
if (!this.active) {
708+
task.pause();
709+
}
697710
this.handlers?.onBegin?.(url, data.expectedBytes);
698711
})
699712
.progress((percent, bytes, total) => {
713+
// Bug: https://github.com/kesha-antonov/react-native-background-downloader/issues/23
714+
// See note in begin() above. We can get progress callbacks even without
715+
// begin() (e.g. in the case of resuming a background task upon launch).
716+
if (!this.active) {
717+
task.pause();
718+
}
700719
this.handlers?.onProgress?.(url, percent, bytes, total);
701720
})
702721
.done(async () => {

test/index.spec.ts

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,54 @@ describe("DownloadQueue", () => {
825825
expect(task.resume).toHaveBeenCalledTimes(1);
826826
});
827827

828+
it("should pause revived url when relaunched inactive", async () => {
829+
const queue = new DownloadQueue();
830+
let assignedId = "tbd";
831+
let progresser: ProgressHandler;
832+
833+
(download as jest.Mock).mockImplementation((spec: { id: string }) => {
834+
assignedId = spec.id;
835+
return task;
836+
});
837+
(ensureDownloadsAreRunning as jest.Mock).mockImplementation(() => {
838+
// This is exactly what the actual implementation does, to work around
839+
// some bug in the library.
840+
task.pause();
841+
task.resume();
842+
});
843+
844+
await queue.init({ domain: "mydomain" });
845+
await queue.addUrl("http://foo.com/a.mp3");
846+
847+
expect(download).toHaveBeenCalledTimes(1);
848+
expect(task.resume).not.toHaveBeenCalled();
849+
850+
(checkForExistingDownloads as jest.Mock).mockReturnValue([
851+
Object.assign(task, {
852+
id: assignedId,
853+
progress: (handler: ProgressHandler) => {
854+
progresser = handler;
855+
return task;
856+
}
857+
}),
858+
]);
859+
860+
task.state = "PAUSED";
861+
862+
// Pretend app got launched again by using another queue
863+
const relaunchQueue = new DownloadQueue();
864+
865+
await relaunchQueue.init({ domain: "mydomain", startActive: false });
866+
expect(task.resume).toHaveBeenCalledTimes(1);
867+
868+
// We now call the progress() handler because we inserted a workaround for
869+
// https://github.com/kesha-antonov/react-native-background-downloader/issues/23
870+
// Revived tasks get progress() without begin(), so we also need to pause
871+
// those cases.
872+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
873+
progresser!(42, 420, 8675309);
874+
});
875+
828876
it("shouldn't re-download revived spec if file already downloaded", async () => {
829877
const queue = new DownloadQueue();
830878
let doner: DoneHandler | undefined;
@@ -1376,6 +1424,7 @@ describe("DownloadQueue", () => {
13761424
describe("Pause / resume", () => {
13771425
it("should start paused if requested on background downloading task", async () => {
13781426
const queue = new DownloadQueue();
1427+
let beginner: BeginHandler;
13791428

13801429
task.state = "DOWNLOADING";
13811430
(checkForExistingDownloads as jest.Mock).mockReturnValue([task]);
@@ -1390,18 +1439,35 @@ describe("DownloadQueue", () => {
13901439
expect(task.resume).not.toHaveBeenCalled();
13911440
// We expect pause TWO times because, according to downloader docs, we
13921441
// should explicitly pause before reattaching handlers; we then pause
1393-
// gain because we specified !startActive.
1442+
// again because we specified !startActive.
13941443
expect(task.pause).toHaveBeenCalledTimes(2);
13951444
expect(download).not.toHaveBeenCalled();
13961445

1397-
(download as jest.Mock).mockReturnValue(task);
1446+
(download as jest.Mock).mockImplementation(
1447+
(spec: { id: string }): TaskWithHandlers => {
1448+
return Object.assign(task, {
1449+
id: spec.id,
1450+
begin: (handler: BeginHandler) => {
1451+
beginner = handler;
1452+
return task;
1453+
},
1454+
});
1455+
}
1456+
);
13981457

13991458
await queue.addUrl("http://boo.com/a.mp3");
1459+
1460+
// We now call the begin() handler because we inserted a workaround for
1461+
// https://github.com/kesha-antonov/react-native-background-downloader/issues/23
1462+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1463+
beginner!({ expectedBytes: 42, headers: {} });
1464+
14001465
expect(task.pause).toHaveBeenCalledTimes(3); // for the added download
14011466
});
14021467

14031468
it("should start paused if requested on paused background task", async () => {
14041469
const queue = new DownloadQueue();
1470+
let beginner: BeginHandler;
14051471

14061472
task.state = "PAUSED";
14071473
(checkForExistingDownloads as jest.Mock).mockReturnValue([task]);
@@ -1417,9 +1483,25 @@ describe("DownloadQueue", () => {
14171483
expect(task.pause).toHaveBeenCalledTimes(1);
14181484
expect(download).not.toHaveBeenCalled();
14191485

1420-
(download as jest.Mock).mockReturnValue(task);
1486+
(download as jest.Mock).mockImplementation(
1487+
(spec: { id: string }): TaskWithHandlers => {
1488+
return Object.assign(task, {
1489+
id: spec.id,
1490+
begin: (handler: BeginHandler) => {
1491+
beginner = handler;
1492+
return task;
1493+
},
1494+
});
1495+
}
1496+
);
14211497

14221498
await queue.addUrl("http://boo.com/a.mp3");
1499+
1500+
// We now call the begin() handler because we inserted a workaround for
1501+
// https://github.com/kesha-antonov/react-native-background-downloader/issues/23
1502+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1503+
beginner!({ expectedBytes: 42, headers: {} });
1504+
14231505
expect(task.pause).toHaveBeenCalledTimes(2); // for the added download
14241506
});
14251507

@@ -1568,13 +1650,32 @@ describe("DownloadQueue", () => {
15681650

15691651
it("should respect the user's !startActive during network change", async () => {
15701652
const queue = new DownloadQueue();
1653+
let beginner: BeginHandler;
1654+
15711655
await queue.init({
15721656
domain: "mydomain",
15731657
netInfoAddEventListener: addEventListener,
15741658
netInfoFetchState: fetch,
15751659
startActive: false,
15761660
});
1661+
1662+
(download as jest.Mock).mockImplementation(
1663+
(spec: { id: string }): TaskWithHandlers => {
1664+
return Object.assign(task, {
1665+
id: spec.id,
1666+
begin: (handler: BeginHandler) => {
1667+
beginner = handler;
1668+
return task;
1669+
},
1670+
});
1671+
}
1672+
);
1673+
15771674
await queue.addUrl("http://foo.com/a.mp3");
1675+
// We now call the begin() handler because we inserted a workaround for
1676+
// https://github.com/kesha-antonov/react-native-background-downloader/issues/23
1677+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1678+
beginner!({ expectedBytes: 42, headers: {} });
15781679
expect(task.pause).toHaveBeenCalledTimes(1);
15791680

15801681
netInfoHandler(createNetState(false));

0 commit comments

Comments
 (0)