🐛 Trying to fix file chunk issue
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user