download method

  1. @override
Future<Result<File>> download(
  1. String url, {
  2. required String savePath,
  3. ProgressCallback? onProgress,
  4. RequestOptions? options,
})
override

Standard one-shot file download.

Implementation

@override
Future<Result<File>> download(
  String url, {
  required String savePath,
  ProgressCallback? onProgress,
  RequestOptions? options,
}) async {
  final uri = Uri.parse(url);
  HttpClientRequest req;
  try {
    req = await _http
        .getUrl(uri)
        .timeout(
          options?.timeout ?? _config.timeout,
          onTimeout: () =>
              throw TimeoutException('Download from $url timed out'),
        );
  } on SocketException catch (e) {
    return Failure(ConnectionException('Cannot reach ${uri.host}', cause: e));
  }

  (options?.headers ?? {}).forEach(req.headers.set);

  late HttpClientResponse response;
  try {
    response = await req.close();
  } catch (e) {
    return Failure(
      UnknownNetworkException('Download request failed: $e', cause: e),
    );
  }

  if (response.statusCode < 200 || response.statusCode >= 300) {
    final body = await _readBody(response);
    return Failure(
      HttpStatusException(
        statusCode: response.statusCode,
        message: 'Download failed with HTTP ${response.statusCode}',
        responseBody: body,
      ),
    );
  }

  final total = response.contentLength; // -1 if unknown
  var received = 0;
  final output = File(savePath);
  final sink = output.openWrite();

  try {
    await for (final chunk in response) {
      sink.add(chunk);
      received += chunk.length;
      if (total > 0) onProgress?.call(received, total);
    }
  } finally {
    await sink.flush();
    await sink.close();
  }

  return Success(output, statusCode: response.statusCode);
}