download method

  1. @override
Future<AdapterResponse> download(
  1. AdapterRequest request,
  2. String savePath, {
  3. ProgressCallback? onProgress,
})
override

Downloads a file from the server.

This method downloads a file and saves it to the specified path on the device. Progress can be tracked using the optional onProgress callback.

Parameters:

  • request: The request configuration for the download
  • savePath: The local file path where the downloaded file will be saved
  • onProgress: Optional callback to track download progress

Returns a Future that completes with an AdapterResponse when the download is complete.

Throws AdapterException if the download fails.

Example:

final request = AdapterRequest(
  baseUrl: 'https://example.com',
  path: '/files/document.pdf',
  method: HttpMethod.get,
);

await adapter.download(
  request,
  '/path/to/save/document.pdf',
  onProgress: (count, total) {
    print('Downloaded: ${(count / total * 100).toStringAsFixed(1)}%');
  },
);

Implementation

@override
Future<AdapterResponse> download(
  AdapterRequest request,
  String savePath, {
  ProgressCallback? onProgress,
}) async {
  final completer = Completer<void>();
  try {
    final baseRequest = await _buildBaseRequest(request);
    if (request.cancelToken != null) {
      _registerCancelToken(request.cancelToken!, completer);
      if (request.cancelToken!.isCancelled) {
        throw AdapterException.cancel(
          message: request.cancelToken!.cancelReason,
        );
      }
    }

    final requestFuture = _client.send(baseRequest);
    final streamedResponse = request.cancelToken != null
        ? await Future.any<http.StreamedResponse>([
            requestFuture,
            completer.future.then((_) => throw AdapterException.cancel(
                  message: request.cancelToken!.cancelReason,
                )),
          ])
        : await requestFuture;

    if (streamedResponse.statusCode >= 400) {
      throw AdapterException(
        message: 'HTTP ${streamedResponse.statusCode}',
        type: AdapterExceptionType.response,
        statusCode: streamedResponse.statusCode,
        response: _convertFromHttpStreamedResponse(streamedResponse, request),
      );
    }

    if (kIsWeb) {
      throw AdapterException(
        message:
            'File download is not supported on Web platform. Use browser download API instead.',
        type: AdapterExceptionType.unknown,
      );
    }

    final file = File(savePath);
    if (!file.parent.existsSync()) {
      file.parent.createSync(recursive: true);
    }
    final sink = file.openWrite();

    try {
      var received = 0;
      final total = streamedResponse.contentLength ?? -1;

      await for (final chunk in _bindCancelToken(
        streamedResponse.stream,
        request.cancelToken,
      )) {
        sink.add(chunk);
        received += chunk.length;
        onProgress?.call(received, total > 0 ? total : received);
      }
    } finally {
      await sink.flush();
      await sink.close();
    }

    final responseHeaders = <String, List<String>>{};
    streamedResponse.headers.forEach((key, value) {
      responseHeaders[key] = [value];
    });

    return AdapterResponse(
      statusCode: streamedResponse.statusCode,
      statusMessage: streamedResponse.reasonPhrase,
      data: savePath,
      headers: responseHeaders,
      request: request,
    );
  } catch (e, stackTrace) {
    if (e is AdapterException) {
      rethrow;
    }
    throw _convertException(e, stackTrace);
  } finally {
    _unregisterCancelToken(request.cancelToken, completer);
  }
}