download method
Downloads a file from the provided url
.
Implementation
Future<File?> download(
String url,
String filename,
int? size, {
String? path,
String? checksum,
Function(int count, int total)? onReceiveProgress,
CancelToken? cancelToken,
bool temporary = false,
int retries = 5,
}) async {
dynamic completeWith;
int tries = 0;
CancelableOperation<File?>? operation;
operation = CancelableOperation.fromFuture(
Future(() async {
// Rethrows the [exception], if any other than `404` is thrown.
void onError(dynamic exception) {
if (exception is! DioException ||
exception.response?.statusCode != 404) {
completeWith = exception;
operation?.cancel();
} else {
++tries;
if (tries <= retries) {
// Continue the [Backoff.run] re-trying.
throw exception;
}
}
}
if (PlatformUtils.isWeb) {
await Backoff.run(() async {
try {
await WebUtils.downloadFile(url, filename);
} catch (e) {
onError(e);
}
}, cancelToken);
} else {
File? file;
if (path == null) {
// Retry fetching the size unless any other that `404` error is
// thrown.
file = await Backoff.run(() async {
try {
return await fileExists(
filename,
size: size,
url: url,
temporary: temporary,
);
} catch (e) {
onError(e);
}
return null;
}, cancelToken);
}
if (file == null) {
Uint8List? data;
if (checksum != null && CacheWorker.instance.exists(checksum)) {
data = (await CacheWorker.instance.get(checksum: checksum)).bytes;
}
if (path == null) {
final String name = p.basenameWithoutExtension(filename);
final String extension = p.extension(filename);
final Directory directory =
temporary
? await temporaryDirectory
: await downloadsDirectory;
file = File('${directory.path}/$filename');
for (int i = 1; await file!.exists(); ++i) {
file = File('${directory.path}/$name ($i)$extension');
}
} else {
file = File(path);
}
if (data == null) {
// Retry the downloading unless any other that `404` error is
// thrown.
await Backoff.run(() async {
try {
// TODO: Cache the response.
await (await dio).download(
url,
file!.path,
onReceiveProgress: onReceiveProgress,
cancelToken: cancelToken,
);
} catch (e) {
onError(e);
}
}, cancelToken);
} else {
await file.writeAsBytes(data);
}
}
return file;
}
return null;
}),
);
cancelToken?.whenCancel.whenComplete(operation.cancel);
final File? result = await operation.valueOrCancellation();
if (completeWith != null) {
throw completeWith;
}
return result;
}