diff --git a/mobile/lib/db/upload_locks_db.dart b/mobile/lib/db/upload_locks_db.dart index 68457fe81..f679911b4 100644 --- a/mobile/lib/db/upload_locks_db.dart +++ b/mobile/lib/db/upload_locks_db.dart @@ -40,15 +40,6 @@ class UploadLocksDB { columnPartETag: "part_etag", columnPartStatus: "part_status", ); - static const trackStatus = ( - pending: "pending", - uploaded: "uploaded", - completed: "completed", - ); - static const _partStatus = ( - pending: "pending", - uploaded: "uploaded", - ); UploadLocksDB._privateConstructor(); static final UploadLocksDB instance = UploadLocksDB._privateConstructor(); @@ -110,7 +101,7 @@ class UploadLocksDB { ${_trackUploadTable.columnFileKey} TEXT NOT NULL, ${_trackUploadTable.columnObjectKey} TEXT NOT NULL, ${_trackUploadTable.columnCompleteUrl} TEXT NOT NULL, - ${_trackUploadTable.columnStatus} TEXT DEFAULT '${trackStatus.pending}' NOT NULL, + ${_trackUploadTable.columnStatus} TEXT DEFAULT '${MultipartStatus.pending.name}' NOT NULL, ${_trackUploadTable.columnPartSize} INTEGER NOT NULL ) ''', @@ -202,7 +193,7 @@ class UploadLocksDB { return rows.isNotEmpty; } - Future<(MultipartUploadURLs, String)> getCachedLinks( + Future getCachedLinks( String localId, String fileHash, ) async { @@ -245,11 +236,16 @@ class UploadLocksDB { objectKey: objectKey, completeURL: row[_trackUploadTable.columnCompleteUrl] as String, partsURLs: partsURLs, - partUploadStatus: partUploadStatus, - partETags: partETags, ); - return (urls, row[_trackUploadTable.columnStatus] as String); + return MultipartInfo( + urls: urls, + status: MultipartStatus.values + .byName(row[_trackUploadTable.columnStatus] as String), + partUploadStatus: partUploadStatus, + partETags: partETags, + partSize: row[_trackUploadTable.columnPartSize] as int, + ); } Future createTrackUploadsEntry( @@ -287,7 +283,7 @@ class UploadLocksDB { _partsTable.columnObjectKey: objectKey, _partsTable.columnPartNumber: i, _partsTable.columnPartUrl: partsURLs[i], - _partsTable.columnPartStatus: _partStatus.pending, + _partsTable.columnPartStatus: PartStatus.pending.name, }, ); } @@ -302,7 +298,7 @@ class UploadLocksDB { await db.update( _partsTable.table, { - _partsTable.columnPartStatus: _partStatus.uploaded, + _partsTable.columnPartStatus: PartStatus.uploaded.name, _partsTable.columnPartETag: etag, }, where: @@ -313,7 +309,7 @@ class UploadLocksDB { Future updateTrackUploadStatus( String objectKey, - String status, + MultipartStatus status, ) async { final db = await instance.database; await db.update( diff --git a/mobile/lib/module/upload/model/multipart.dart b/mobile/lib/module/upload/model/multipart.dart index c32c054c4..cda72d141 100644 --- a/mobile/lib/module/upload/model/multipart.dart +++ b/mobile/lib/module/upload/model/multipart.dart @@ -18,19 +18,42 @@ class PartETag extends XmlParsableObject { } } +enum MultipartStatus { + pending, + uploaded, + completed, +} + +enum PartStatus { + pending, + uploaded, +} + +class MultipartInfo { + final List? partUploadStatus; + final Map? partETags; + final int? partSize; + final MultipartUploadURLs urls; + final MultipartStatus status; + + MultipartInfo({ + this.partUploadStatus, + this.partETags, + this.partSize, + this.status = MultipartStatus.pending, + required this.urls, + }); +} + class MultipartUploadURLs { final String objectKey; final List partsURLs; final String completeURL; - final List? partUploadStatus; - final Map? partETags; MultipartUploadURLs({ required this.objectKey, required this.partsURLs, required this.completeURL, - this.partUploadStatus, - this.partETags, }); factory MultipartUploadURLs.fromMap(Map map) { diff --git a/mobile/lib/module/upload/service/multipart.dart b/mobile/lib/module/upload/service/multipart.dart index 2e0c43fc5..3ea84bad4 100644 --- a/mobile/lib/module/upload/service/multipart.dart +++ b/mobile/lib/module/upload/service/multipart.dart @@ -22,7 +22,7 @@ class MultiPartUploader { this._s3Dio, this._db, this._featureFlagService, - ) {} + ); Future calculatePartCount(int fileSize) async { final partCount = (fileSize / multipartPartSizeForUpload).ceil(); @@ -72,21 +72,25 @@ class MultiPartUploader { String localId, String fileHash, ) async { - final (urls, status) = await _db.getCachedLinks(localId, fileHash); + final multipartInfo = await _db.getCachedLinks(localId, fileHash); - Map etags = urls.partETags ?? {}; + Map etags = multipartInfo.partETags ?? {}; - if (status == UploadLocksDB.trackStatus.pending) { + if (multipartInfo.status == MultipartStatus.pending) { // upload individual parts and get their etags - etags = await _uploadParts(urls, encryptedFile); + etags = await _uploadParts(multipartInfo, encryptedFile); } - if (status != UploadLocksDB.trackStatus.completed) { + if (multipartInfo.status != MultipartStatus.completed) { // complete the multipart upload - await _completeMultipartUpload(urls.objectKey, etags, urls.completeURL); + await _completeMultipartUpload( + multipartInfo.urls.objectKey, + etags, + multipartInfo.urls.completeURL, + ); } - return urls.objectKey; + return multipartInfo.urls.objectKey; } Future putMultipartFile( @@ -94,7 +98,10 @@ class MultiPartUploader { File encryptedFile, ) async { // upload individual parts and get their etags - final etags = await _uploadParts(urls, encryptedFile); + final etags = await _uploadParts( + MultipartInfo(urls: urls), + encryptedFile, + ); // complete the multipart upload await _completeMultipartUpload(urls.objectKey, etags, urls.completeURL); @@ -103,30 +110,30 @@ class MultiPartUploader { } Future> _uploadParts( - MultipartUploadURLs url, + MultipartInfo partInfo, File encryptedFile, ) async { - final partsURLs = url.partsURLs; - final partUploadStatus = url.partUploadStatus; + final partsURLs = partInfo.urls.partsURLs; + final partUploadStatus = partInfo.partUploadStatus; final partsLength = partsURLs.length; - final etags = url.partETags ?? {}; + final etags = partInfo.partETags ?? {}; for (int i = 0; i < partsLength; i++) { if (i < (partUploadStatus?.length ?? 0) && (partUploadStatus?[i] ?? false)) { continue; } + final partSize = partInfo.partSize ?? multipartPartSizeForUpload; final partURL = partsURLs[i]; final isLastPart = i == partsLength - 1; - final fileSize = isLastPart - ? encryptedFile.lengthSync() % multipartPartSizeForUpload - : multipartPartSizeForUpload; + final fileSize = + isLastPart ? encryptedFile.lengthSync() % partSize : partSize; final response = await _s3Dio.put( partURL, data: encryptedFile.openRead( - i * multipartPartSizeForUpload, - isLastPart ? null : (i + 1) * multipartPartSizeForUpload, + i * partSize, + isLastPart ? null : (i + 1) * partSize, ), options: Options( headers: { @@ -143,11 +150,11 @@ class MultiPartUploader { etags[i] = eTag!; - await _db.updatePartStatus(url.objectKey, i, eTag); + await _db.updatePartStatus(partInfo.urls.objectKey, i, eTag); } await _db.updateTrackUploadStatus( - url.objectKey, - UploadLocksDB.trackStatus.uploaded, + partInfo.urls.objectKey, + MultipartStatus.uploaded, ); return etags; @@ -179,7 +186,7 @@ class MultiPartUploader { ); await _db.updateTrackUploadStatus( objectKey, - UploadLocksDB.trackStatus.completed, + MultipartStatus.completed, ); } catch (e) { Logger("MultipartUpload").severe(e);