2.dart_ 2.96 KB
import 'package:dio/dio.dart';

class ParallelUploader {
  final Dio dio = Dio();
  final int maxConcurrentUploads;
  
  ParallelUploader({this.maxConcurrentUploads = 3});

  // 并行上传多个分片
  Future<List<UploadResult>> uploadChunksParallel(
    File file, 
    List<ChunkInfo> chunks,
    String uploadUrl,
  ) async {
    final results = <UploadResult>[];
    final completed = <bool>[];
    
    // 使用队列控制并发数量
    for (int i = 0; i < chunks.length; i += maxConcurrentUploads) {
      final currentBatch = chunks.sublist(
        i, 
        i + maxConcurrentUploads > chunks.length ? chunks.length : i + maxConcurrentUploads
      );
      
      // 并行上传当前批次的分片
      final batchFutures = currentBatch.map((chunk) {
        return compute(_uploadSingleChunk, UploadTask(
          filePath: file.path,
          chunk: chunk,
          uploadUrl: uploadUrl,
        ));
      }).toList();
      
      final batchResults = await Future.wait(batchFutures);
      results.addAll(batchResults);
      
      // 更新进度
      _updateProgress(results.length, chunks.length);
    }
    
    return results;
  }
  
  void _updateProgress(int completed, int total) {
    final progress = (completed / total * 100).toInt();
    print('上传进度: $progress%');
  }
}

// 上传任务数据类(必须是可序列化的)
class UploadTask {
  final String filePath;
  final ChunkInfo chunk;
  final String uploadUrl;
  
  UploadTask({
    required this.filePath,
    required this.chunk,
    required this.uploadUrl,
  });
}

// 上传结果类
class UploadResult {
  final int chunkIndex;
  final bool success;
  final String? error;
  final String? chunkId;
  
  UploadResult({
    required this.chunkIndex,
    required this.success,
    this.error,
    this.chunkId,
  });
}

// 在后台线程上传单个分片
Future<UploadResult> _uploadSingleChunk(UploadTask task) async {
  try {
    final file = File(task.filePath);
    final chunk = task.chunk;
    
    // 读取分片数据
    final raf = file.openSync();
    raf.setPositionSync(chunk.start);
    final chunkData = raf.readSync(chunk.end - chunk.start);
    raf.closeSync();
    
    // 上传分片
    final dio = Dio();
    final formData = FormData.fromMap({
      'file': MultipartFile.fromBytes(
        chunkData, 
        filename: 'chunk-${chunk.index}'
      ),
      'chunkIndex': chunk.index,
      'totalChunks': chunk.totalChunks,
      'chunkSize': chunk.end - chunk.start,
    });
    
    final response = await dio.post(
      task.uploadUrl,
      data: formData,
      options: Options(
        sendTimeout: Duration(seconds: 30),
        receiveTimeout: Duration(seconds: 30),
      ),
    );
    
    return UploadResult(
      chunkIndex: chunk.index,
      success: response.statusCode == 200,
      chunkId: response.data['chunkId'],
    );
  } catch (e) {
    return UploadResult(
      chunkIndex: task.chunk.index,
      success: false,
      error: e.toString(),
    );
  }
}