🐛 Trying to fix file chunk issue

This commit is contained in:
2025-11-05 13:13:21 +08:00
parent f5f1ddc0ea
commit d4758674bb

View File

@@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:cross_file/cross_file.dart'; import 'package:cross_file/cross_file.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
@@ -16,16 +15,15 @@ class FileUploader {
FileUploader(this._client); FileUploader(this._client);
/// Calculates the MD5 hash of a file. /// Calculates the MD5 hash of file bytes.
Future<String> _calculateFileHash(XFile file) async { String _calculateFileHash(Uint8List bytes) {
final bytes = await file.readAsBytes();
final digest = md5.convert(bytes); final digest = md5.convert(bytes);
return digest.toString(); return digest.toString();
} }
/// Creates an upload task for the given file. /// Creates an upload task for the given file.
Future<Map<String, dynamic>> createUploadTask({ Future<Map<String, dynamic>> createUploadTask({
required XFile file, required Uint8List bytes,
required String fileName, required String fileName,
required String contentType, required String contentType,
String? poolId, String? poolId,
@@ -34,8 +32,8 @@ class FileUploader {
String? expiredAt, String? expiredAt,
int? chunkSize, int? chunkSize,
}) async { }) async {
final hash = await _calculateFileHash(file); final hash = _calculateFileHash(bytes);
final fileSize = await file.length(); final fileSize = bytes.length;
final response = await _client.post( final response = await _client.post(
'/drive/files/upload/create', '/drive/files/upload/create',
@@ -83,7 +81,7 @@ class FileUploader {
/// Uploads a file in chunks using the multi-part API. /// Uploads a file in chunks using the multi-part API.
Future<SnCloudFile> uploadFile({ Future<SnCloudFile> uploadFile({
required XFile file, required Uint8List bytes,
required String fileName, required String fileName,
required String contentType, required String contentType,
String? poolId, String? poolId,
@@ -94,7 +92,7 @@ class FileUploader {
}) async { }) async {
// Step 1: Create upload task // Step 1: Create upload task
final createResponse = await createUploadTask( final createResponse = await createUploadTask(
file: file, bytes: bytes,
fileName: fileName, fileName: fileName,
contentType: contentType, contentType: contentType,
poolId: poolId, poolId: poolId,
@@ -114,24 +112,10 @@ class FileUploader {
final chunksCount = createResponse['chunks_count'] as int; final chunksCount = createResponse['chunks_count'] as int;
// Step 2: Upload chunks // Step 2: Upload chunks
final stream = file.openRead();
final chunks = <Uint8List>[]; final chunks = <Uint8List>[];
int bytesRead = 0; for (int i = 0; i < bytes.length; i += chunkSize) {
final buffer = BytesBuilder(); final end = i + chunkSize > bytes.length ? bytes.length : i + chunkSize;
chunks.add(Uint8List.fromList(bytes.sublist(i, end)));
await for (final chunk in stream) {
buffer.add(chunk);
bytesRead += chunk.length;
if (bytesRead >= chunkSize) {
chunks.add(buffer.takeBytes());
bytesRead = 0;
}
}
// Add remaining bytes as last chunk
if (buffer.length > 0) {
chunks.add(buffer.takeBytes());
} }
// Ensure we have the correct number of chunks // Ensure we have the correct number of chunks
@@ -225,20 +209,34 @@ class FileUploader {
Completer<SnCloudFile?> completer, Completer<SnCloudFile?> completer,
) { ) {
String actualMimetype = getMimeType(fileData); String actualMimetype = getMimeType(fileData);
late XFile file;
String actualFilename = fileData.displayName ?? 'randomly_file'; String actualFilename = fileData.displayName ?? 'randomly_file';
Uint8List? byteData; Uint8List? bytes;
// Handle the data based on what's in the UniversalFile // Handle the data based on what's in the UniversalFile
final data = fileData.data; final data = fileData.data;
if (data is XFile) { if (data is XFile) {
file = data; // Read bytes from XFile
actualFilename = fileData.displayName ?? data.name; data
.readAsBytes()
.then((readBytes) {
_performUpload(
bytes: readBytes,
fileName: fileData.displayName ?? data.name,
contentType: actualMimetype,
client: client,
poolId: poolId,
onProgress: onProgress,
completer: completer,
);
})
.catchError((e) {
completer.completeError(e);
});
return completer;
} else if (data is List<int> || data is Uint8List) { } else if (data is List<int> || data is Uint8List) {
byteData = data is List<int> ? Uint8List.fromList(data) : data; bytes = data is List<int> ? Uint8List.fromList(data) : data;
actualFilename = fileData.displayName ?? 'uploaded_file'; actualFilename = fileData.displayName ?? 'uploaded_file';
file = XFile.fromData(byteData!, mimeType: actualMimetype);
} else if (data is SnCloudFile) { } else if (data is SnCloudFile) {
// If the file is already on the cloud, just return it // If the file is already on the cloud, just return it
completer.complete(data); completer.complete(data);
@@ -252,15 +250,40 @@ class FileUploader {
return completer; return completer;
} }
if (bytes != null) {
_performUpload(
bytes: bytes,
fileName: actualFilename,
contentType: actualMimetype,
client: client,
poolId: poolId,
onProgress: onProgress,
completer: completer,
);
}
return completer;
}
// Helper method to perform the actual upload
static void _performUpload({
required Uint8List bytes,
required String fileName,
required String contentType,
required Dio client,
String? poolId,
Function(double progress, Duration estimate)? onProgress,
required Completer<SnCloudFile?> completer,
}) {
final uploader = FileUploader(client); final uploader = FileUploader(client);
// Call progress start // Call progress start
onProgress?.call(0.0, Duration.zero); onProgress?.call(0.0, Duration.zero);
uploader uploader
.uploadFile( .uploadFile(
file: file, bytes: bytes,
fileName: actualFilename, fileName: fileName,
contentType: actualMimetype, contentType: contentType,
poolId: poolId, poolId: poolId,
) )
.then((result) { .then((result) {
@@ -272,8 +295,6 @@ class FileUploader {
completer.completeError(e); completer.completeError(e);
throw e; throw e;
}); });
return completer;
} }
/// Gets the MIME type of a UniversalFile. /// Gets the MIME type of a UniversalFile.