breakPointDownload method
void
breakPointDownload({
- required String savePath,
- ProgressCallback? onReceiveProgress,
- Success? success,
- Failure? failure,
- Completed? completed,
- dynamic cancelCallback()?,
断点下载
Implementation
void breakPointDownload({
required String savePath,
adapter.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();
}
// 添加 Range 头部
final headers = _buildHeaders();
headers["Range"] = "bytes=$downloadStart-";
// 准备请求体
dynamic requestBody = _rawBody;
if (_rawBody == null && _bodyParams.isNotEmpty) {
if (_bodyType == RequestBodyType.formData) {
requestBody = _bodyParams;
} else if (_bodyType == RequestBodyType.json) {
requestBody = _bodyParams;
}
}
// 构建 AdapterRequest,外部通常需要将responseType设置为 stream 响应类型
final adapterRequest = adapter_models.AdapterRequest(
baseUrl: _rxNet.baseUrl,
path: url,
method: _HttpMethod,
queryParams: _queryParams,
headers: headers,
rawBody: requestBody,
contentType: _contentType,
responseType: _convertResponseType(),
sendTimeout: _sendTimeout,
receiveTimeout: _receiveTimeout,
cancelToken: _cancelToken, // Use the actual cancel token
);
// 使用适配器发送请求
final adapter = _rxNet.getAdapter();
if (adapter == null) {
throw NetworkException("NetworkAdapter is not initialized", null);
}
final response = await adapter.request(adapterRequest);
onResponse?.call(response);
// 处理流式响应
if (response.data is Stream<List<int>>) {
RandomAccessFile raf = file.openSync(mode: FileMode.append);
Stream<Uint8List> stream = (response.data as Stream<List<int>>).map((data) => Uint8List.fromList(data));
// 获取总大小
final contentRange = response.getHeader('content-range');
final total = int.tryParse(contentRange?.split('/').last ?? "0") ?? 0;
final subscription = stream.listen((data) {
raf.writeFromSync(data);
downloadStart = downloadStart + data.length;
if (total > 0 && 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);
// 处理取消(简化版本,因为我们现在使用字符串标识)
// 实际的取消逻辑由适配器处理
} else {
// 如果不是流式响应,检查是否已完成
final contentRange = response.getHeader('content-range');
final total = int.tryParse(contentRange?.split('/').last ?? "0") ?? 0;
if (total <= downloadStart) {
onReceiveProgress?.call(total, total);
success?.call(file, SourcesType.net);
}
}
} on AdapterException catch (error) {
if (error.type == AdapterExceptionType.cancel) {
cancelCallback?.call();
} else {
failure?.call(error);
}
} catch (e) {
failure?.call(e);
}
completed?.call();
}