diff --git a/mobile/lib/db/upload_locks_db.dart b/mobile/lib/db/upload_locks_db.dart index a8b490762..827765047 100644 --- a/mobile/lib/db/upload_locks_db.dart +++ b/mobile/lib/db/upload_locks_db.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; +import "package:photos/core/constants.dart"; import "package:photos/utils/multipart_upload_util.dart"; import 'package:sqflite/sqflite.dart'; @@ -31,6 +32,11 @@ class UploadLocksDB { columnPartSize: "part_size", ); + static const _trackStatus = ( + pending: "pending", + completed: "completed", + ); + static const _partsTable = ( table: "upload_parts", columnObjectKey: "object_key", @@ -38,6 +44,10 @@ class UploadLocksDB { columnPartUrl: "part_url", columnPartStatus: "part_status", ); + static const _partStatus = ( + pending: "pending", + uploaded: "uploaded", + ); UploadLocksDB._privateConstructor(); static final UploadLocksDB instance = UploadLocksDB._privateConstructor(); @@ -210,4 +220,74 @@ class UploadLocksDB { return urls; } + + Future createTrackUploadsEntry( + String localId, + String fileHash, + MultipartUploadURLs urls, + String encryptedFilePath, + int fileSize, + ) async { + final db = await UploadLocksDB.instance.database; + final objectKey = urls.objectKey; + + await db.insert( + _trackUploadTable.table, + { + _trackUploadTable.columnLocalID: localId, + _trackUploadTable.columnFileHash: fileHash, + _trackUploadTable.columnObjectKey: objectKey, + _trackUploadTable.columnCompleteUrl: urls.completeURL, + _trackUploadTable.columnEncryptedFilePath: encryptedFilePath, + _trackUploadTable.columnEncryptedFileSize: fileSize, + _trackUploadTable.columnCompletionStatus: _trackStatus.pending, + _trackUploadTable.columnPartSize: multipartPartSize, + }, + ); + + final partsURLs = urls.partsURLs; + final partsLength = partsURLs.length; + + for (int i = 0; i < partsLength; i++) { + await db.insert( + _partsTable.table, + { + _partsTable.columnObjectKey: objectKey, + _partsTable.columnPartNumber: i, + _partsTable.columnPartUrl: partsURLs[i], + _partsTable.columnPartStatus: _partStatus.pending, + }, + ); + } + } + + Future updatePartStatus( + String objectKey, + int partNumber, + ) async { + final db = await instance.database; + await db.update( + _partsTable.table, + { + _partsTable.columnPartStatus: _partStatus.uploaded, + }, + where: + '${_partsTable.columnObjectKey} = ? AND ${_partsTable.columnPartNumber} = ?', + whereArgs: [objectKey, partNumber], + ); + } + + Future updateCompletionStatus( + String objectKey, + ) async { + final db = await instance.database; + await db.update( + _trackUploadTable.table, + { + _trackUploadTable.columnCompletionStatus: _trackStatus.completed, + }, + where: '${_trackUploadTable.columnObjectKey} = ?', + whereArgs: [objectKey], + ); + } } diff --git a/mobile/lib/utils/file_uploader.dart b/mobile/lib/utils/file_uploader.dart index f2f8ee589..c336a99b1 100644 --- a/mobile/lib/utils/file_uploader.dart +++ b/mobile/lib/utils/file_uploader.dart @@ -515,6 +515,14 @@ class FileUploader { ); } else { final fileUploadURLs = await getMultipartUploadURLs(count); + + await createTableEntry( + lockKey, + mediaUploadData.hashData!.fileHash!, + fileUploadURLs, + encryptedFilePath, + await encryptedFile.length(), + ); fileObjectKey = await putMultipartFile(fileUploadURLs, encryptedFile); } } diff --git a/mobile/lib/utils/multipart_upload_util.dart b/mobile/lib/utils/multipart_upload_util.dart index 279610564..f5bb12372 100644 --- a/mobile/lib/utils/multipart_upload_util.dart +++ b/mobile/lib/utils/multipart_upload_util.dart @@ -73,6 +73,22 @@ Future getMultipartUploadURLs(int count) async { } } +Future createTableEntry( + String localId, + String fileHash, + MultipartUploadURLs urls, + String encryptedFilePath, + int fileSize, +) async { + await UploadLocksDB.instance.createTrackUploadsEntry( + localId, + fileHash, + urls, + encryptedFilePath, + fileSize, + ); +} + Future putExistingMultipartFile( File encryptedFile, String localId, @@ -84,7 +100,7 @@ Future putExistingMultipartFile( final etags = await uploadParts(urls, encryptedFile); // complete the multipart upload - await completeMultipartUpload(etags, urls.completeURL); + await completeMultipartUpload(urls.objectKey, etags, urls.completeURL); return urls.objectKey; } @@ -97,7 +113,7 @@ Future putMultipartFile( final etags = await uploadParts(urls, encryptedFile); // complete the multipart upload - await completeMultipartUpload(etags, urls.completeURL); + await completeMultipartUpload(urls.objectKey, etags, urls.completeURL); return urls.objectKey; } @@ -141,12 +157,15 @@ Future> uploadParts( } etags[i] = eTag!; + + await UploadLocksDB.instance.updatePartStatus(url.objectKey, i); } return etags; } Future completeMultipartUpload( + String objectKey, Map partEtags, String completeURL, ) async { @@ -169,6 +188,7 @@ Future completeMultipartUpload( contentType: "text/xml", ), ); + await UploadLocksDB.instance.updateCompletionStatus(objectKey); } catch (e) { Logger("MultipartUpload").severe(e); rethrow;