breakPointDownload method

void breakPointDownload({
  1. required String savePath,
  2. ProgressCallback? onReceiveProgress,
  3. Success? success,
  4. Failure? failure,
  5. Completed? completed,
  6. dynamic cancelCallback()?,
})

断点下载

Implementation

void breakPointDownload({
  required String savePath,
  ProgressCallback? onReceiveProgress,
  Success? success,
  Failure? failure,
  Completed? completed,
  Function()? cancelCallback,
}) async {
  if (!(await _checkNetWork())) {
    return;
  }

  int downloadStart = 0;
  File file = File(savePath);

  try {
    final url = _buildFinalUrl();

    if (file.existsSync()) {
      downloadStart = file.lengthSync();
    }

    _options?.method = _httpType.name;
    _options = _options?.copyWith(
      responseType: ResponseType.stream,
    );

    if (_headers.isNotEmpty) {
      _options?.headers?.addAll(_headers);
    }
    if (_enableGlobalHeader) {
      _options?.headers ??= {};
      _options?.headers?.addAll(_rxNet.getHeaders());
    }
    _options?.headers?.addAll({"Range": "bytes=$downloadStart-"});

    // 准备请求体
    dynamic requestBody = _rawBody;
    if (_rawBody == null && _bodyParams.isNotEmpty) {
      if (_bodyType == RequestBodyType.formData) {
        requestBody = FormData.fromMap(_bodyParams);
      } else if (_bodyType == RequestBodyType.json) {
        requestBody = _bodyParams;
      }
    }

    final response = await _rxNet.client!.request<ResponseBody>(
      url,
      options: _options,
      cancelToken: _cancelToken,
      data: requestBody,
      queryParameters: _queryParams,
    );

    onResponse?.call(response);
    RandomAccessFile raf = file.openSync(mode: FileMode.append);
    Stream<Uint8List> stream = response.data!.stream;

    final content = await getContentLength(response);
    final total = int.tryParse(content?.split('/').last ?? "0") ?? 0;

    final subscription = stream.listen((data) {
      raf.writeFromSync(data);
      downloadStart = downloadStart + data.length;
      if (total < downloadStart) {
        onReceiveProgress?.call(total, total);
        return;
      }
      onReceiveProgress?.call(downloadStart, total);
    }, onDone: () async {
      success?.call(file, SourcesType.net);
      await raf.close();
    }, onError: (e) async {
      failure?.call(e);
      await raf.close();
    }, cancelOnError: true);

    _cancelToken?.whenCancel.then((_) async {
      await subscription.cancel();
      await raf.close();
      cancelCallback?.call();
    });
  } on DioException catch (error) {
    if (error.response != null) {
      final content = await getContentLength(error.response!);
      final total = int.tryParse(content?.split('/').last ?? "0") ?? 0;
      if (total <= downloadStart) {
        onReceiveProgress?.call(total, total);
        success?.call(file, SourcesType.net);
      }
    }
    if (CancelToken.isCancel(error)) {
      cancelCallback?.call();
    } else {
      failure?.call(error);
    }
  }

  completed?.call();
}