mirror of
https://github.com/ente-io/ente.git
synced 2025-08-14 02:07:33 +00:00
fix: don't re-encrypt file, add nonce field, upload parts logic
This commit is contained in:
@@ -4,12 +4,14 @@ import 'dart:io';
|
|||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import "package:photos/core/constants.dart";
|
import "package:photos/core/constants.dart";
|
||||||
|
import "package:photos/models/encryption_result.dart";
|
||||||
import "package:photos/module/upload/model/multipart.dart";
|
import "package:photos/module/upload/model/multipart.dart";
|
||||||
|
import "package:photos/utils/crypto_util.dart";
|
||||||
import 'package:sqflite/sqflite.dart';
|
import 'package:sqflite/sqflite.dart';
|
||||||
|
import "package:sqflite_migration/sqflite_migration.dart";
|
||||||
|
|
||||||
class UploadLocksDB {
|
class UploadLocksDB {
|
||||||
static const _databaseName = "ente.upload_locks.db";
|
static const _databaseName = "ente.upload_locks.db";
|
||||||
static const _databaseVersion = 1;
|
|
||||||
|
|
||||||
static const _uploadLocksTable = (
|
static const _uploadLocksTable = (
|
||||||
table: "upload_locks",
|
table: "upload_locks",
|
||||||
@@ -26,6 +28,7 @@ class UploadLocksDB {
|
|||||||
columnEncryptedFilePath: "encrypted_file_path",
|
columnEncryptedFilePath: "encrypted_file_path",
|
||||||
columnEncryptedFileSize: "encrypted_file_size",
|
columnEncryptedFileSize: "encrypted_file_size",
|
||||||
columnFileKey: "file_key",
|
columnFileKey: "file_key",
|
||||||
|
columnFileNonce: "file_nonce",
|
||||||
columnObjectKey: "object_key",
|
columnObjectKey: "object_key",
|
||||||
columnCompleteUrl: "complete_url",
|
columnCompleteUrl: "complete_url",
|
||||||
columnStatus: "status",
|
columnStatus: "status",
|
||||||
@@ -41,6 +44,19 @@ class UploadLocksDB {
|
|||||||
columnPartStatus: "part_status",
|
columnPartStatus: "part_status",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static final initializationScript = [
|
||||||
|
..._createUploadLocksTable(),
|
||||||
|
];
|
||||||
|
|
||||||
|
static final migrationScripts = [
|
||||||
|
..._createTrackUploadsTable(),
|
||||||
|
];
|
||||||
|
|
||||||
|
final dbConfig = MigrationConfig(
|
||||||
|
initializationScript: initializationScript,
|
||||||
|
migrationScripts: migrationScripts,
|
||||||
|
);
|
||||||
|
|
||||||
UploadLocksDB._privateConstructor();
|
UploadLocksDB._privateConstructor();
|
||||||
static final UploadLocksDB instance = UploadLocksDB._privateConstructor();
|
static final UploadLocksDB instance = UploadLocksDB._privateConstructor();
|
||||||
|
|
||||||
@@ -55,18 +71,11 @@ class UploadLocksDB {
|
|||||||
await getApplicationDocumentsDirectory();
|
await getApplicationDocumentsDirectory();
|
||||||
final String path = join(documentsDirectory.path, _databaseName);
|
final String path = join(documentsDirectory.path, _databaseName);
|
||||||
|
|
||||||
return await openDatabase(
|
return await openDatabaseWithMigration(path, dbConfig);
|
||||||
path,
|
|
||||||
version: _databaseVersion,
|
|
||||||
onCreate: _onCreate,
|
|
||||||
onOpen: (db) async {
|
|
||||||
await _createTrackUploadsTable(db);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _onCreate(Database db, int version) async {
|
static List<String> _createUploadLocksTable() {
|
||||||
await db.execute(
|
return [
|
||||||
'''
|
'''
|
||||||
CREATE TABLE ${_uploadLocksTable.table} (
|
CREATE TABLE ${_uploadLocksTable.table} (
|
||||||
${_uploadLocksTable.columnID} TEXT PRIMARY KEY NOT NULL,
|
${_uploadLocksTable.columnID} TEXT PRIMARY KEY NOT NULL,
|
||||||
@@ -74,23 +83,11 @@ class UploadLocksDB {
|
|||||||
${_uploadLocksTable.columnTime} TEXT NOT NULL
|
${_uploadLocksTable.columnTime} TEXT NOT NULL
|
||||||
)
|
)
|
||||||
''',
|
''',
|
||||||
);
|
];
|
||||||
await _createTrackUploadsTable(db);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _createTrackUploadsTable(Database db) async {
|
static List<String> _createTrackUploadsTable() {
|
||||||
if ((await db.query(
|
return [
|
||||||
'sqlite_master',
|
|
||||||
where: 'name = ?',
|
|
||||||
whereArgs: [
|
|
||||||
_trackUploadTable.table,
|
|
||||||
],
|
|
||||||
))
|
|
||||||
.isNotEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.execute(
|
|
||||||
'''
|
'''
|
||||||
CREATE TABLE ${_trackUploadTable.table} (
|
CREATE TABLE ${_trackUploadTable.table} (
|
||||||
${_trackUploadTable.columnID} INTEGER PRIMARY KEY,
|
${_trackUploadTable.columnID} INTEGER PRIMARY KEY,
|
||||||
@@ -99,14 +96,13 @@ class UploadLocksDB {
|
|||||||
${_trackUploadTable.columnEncryptedFilePath} TEXT NOT NULL,
|
${_trackUploadTable.columnEncryptedFilePath} TEXT NOT NULL,
|
||||||
${_trackUploadTable.columnEncryptedFileSize} INTEGER NOT NULL,
|
${_trackUploadTable.columnEncryptedFileSize} INTEGER NOT NULL,
|
||||||
${_trackUploadTable.columnFileKey} TEXT NOT NULL,
|
${_trackUploadTable.columnFileKey} TEXT NOT NULL,
|
||||||
|
${_trackUploadTable.columnFileNonce} TEXT NOT NULL,
|
||||||
${_trackUploadTable.columnObjectKey} TEXT NOT NULL,
|
${_trackUploadTable.columnObjectKey} TEXT NOT NULL,
|
||||||
${_trackUploadTable.columnCompleteUrl} TEXT NOT NULL,
|
${_trackUploadTable.columnCompleteUrl} TEXT NOT NULL,
|
||||||
${_trackUploadTable.columnStatus} TEXT DEFAULT '${MultipartStatus.pending.name}' NOT NULL,
|
${_trackUploadTable.columnStatus} TEXT DEFAULT '${MultipartStatus.pending.name}' NOT NULL,
|
||||||
${_trackUploadTable.columnPartSize} INTEGER NOT NULL
|
${_trackUploadTable.columnPartSize} INTEGER NOT NULL
|
||||||
)
|
)
|
||||||
''',
|
''',
|
||||||
);
|
|
||||||
await db.execute(
|
|
||||||
'''
|
'''
|
||||||
CREATE TABLE ${_partsTable.table} (
|
CREATE TABLE ${_partsTable.table} (
|
||||||
${_partsTable.columnObjectKey} TEXT NOT NULL REFERENCES ${_trackUploadTable.table}(${_trackUploadTable.columnObjectKey}) ON DELETE CASCADE,
|
${_partsTable.columnObjectKey} TEXT NOT NULL REFERENCES ${_trackUploadTable.table}(${_trackUploadTable.columnObjectKey}) ON DELETE CASCADE,
|
||||||
@@ -117,7 +113,7 @@ class UploadLocksDB {
|
|||||||
PRIMARY KEY (${_partsTable.columnObjectKey}, ${_partsTable.columnPartNumber})
|
PRIMARY KEY (${_partsTable.columnObjectKey}, ${_partsTable.columnPartNumber})
|
||||||
)
|
)
|
||||||
''',
|
''',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clearTable() async {
|
Future<void> clearTable() async {
|
||||||
@@ -193,6 +189,33 @@ class UploadLocksDB {
|
|||||||
return rows.isNotEmpty;
|
return rows.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<EncryptionResult> getFileEncryptionData(
|
||||||
|
String localId,
|
||||||
|
String fileHash,
|
||||||
|
) async {
|
||||||
|
final db = await instance.database;
|
||||||
|
|
||||||
|
final rows = await db.query(
|
||||||
|
_trackUploadTable.table,
|
||||||
|
where:
|
||||||
|
'${_trackUploadTable.columnLocalID} = ? AND ${_trackUploadTable.columnFileHash} = ?',
|
||||||
|
whereArgs: [localId, fileHash],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rows.isEmpty) {
|
||||||
|
throw Exception("No cached links found for $localId and $fileHash");
|
||||||
|
}
|
||||||
|
final row = rows.first;
|
||||||
|
|
||||||
|
return EncryptionResult(
|
||||||
|
key:
|
||||||
|
CryptoUtil.base642bin(row[_trackUploadTable.columnFileKey] as String),
|
||||||
|
header: CryptoUtil.base642bin(
|
||||||
|
row[_trackUploadTable.columnFileNonce] as String,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<MultipartInfo> getCachedLinks(
|
Future<MultipartInfo> getCachedLinks(
|
||||||
String localId,
|
String localId,
|
||||||
String fileHash,
|
String fileHash,
|
||||||
@@ -255,6 +278,7 @@ class UploadLocksDB {
|
|||||||
String encryptedFilePath,
|
String encryptedFilePath,
|
||||||
int fileSize,
|
int fileSize,
|
||||||
String fileKey,
|
String fileKey,
|
||||||
|
String fileNonce,
|
||||||
) async {
|
) async {
|
||||||
final db = await UploadLocksDB.instance.database;
|
final db = await UploadLocksDB.instance.database;
|
||||||
final objectKey = urls.objectKey;
|
final objectKey = urls.objectKey;
|
||||||
@@ -269,6 +293,7 @@ class UploadLocksDB {
|
|||||||
_trackUploadTable.columnEncryptedFilePath: encryptedFilePath,
|
_trackUploadTable.columnEncryptedFilePath: encryptedFilePath,
|
||||||
_trackUploadTable.columnEncryptedFileSize: fileSize,
|
_trackUploadTable.columnEncryptedFileSize: fileSize,
|
||||||
_trackUploadTable.columnFileKey: fileKey,
|
_trackUploadTable.columnFileKey: fileKey,
|
||||||
|
_trackUploadTable.columnFileNonce: fileNonce,
|
||||||
_trackUploadTable.columnPartSize: multipartPartSizeForUpload,
|
_trackUploadTable.columnPartSize: multipartPartSizeForUpload,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -315,14 +340,14 @@ class UploadLocksDB {
|
|||||||
await db.update(
|
await db.update(
|
||||||
_trackUploadTable.table,
|
_trackUploadTable.table,
|
||||||
{
|
{
|
||||||
_trackUploadTable.columnStatus: status,
|
_trackUploadTable.columnStatus: status.name,
|
||||||
},
|
},
|
||||||
where: '${_trackUploadTable.columnObjectKey} = ?',
|
where: '${_trackUploadTable.columnObjectKey} = ?',
|
||||||
whereArgs: [objectKey],
|
whereArgs: [objectKey],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> deleteCompletedRecord(
|
Future<int> deleteMultipartTrack(
|
||||||
String localId,
|
String localId,
|
||||||
) async {
|
) async {
|
||||||
final db = await instance.database;
|
final db = await instance.database;
|
||||||
|
@@ -5,6 +5,7 @@ import "package:dio/dio.dart";
|
|||||||
import "package:logging/logging.dart";
|
import "package:logging/logging.dart";
|
||||||
import "package:photos/core/constants.dart";
|
import "package:photos/core/constants.dart";
|
||||||
import "package:photos/db/upload_locks_db.dart";
|
import "package:photos/db/upload_locks_db.dart";
|
||||||
|
import "package:photos/models/encryption_result.dart";
|
||||||
import "package:photos/module/upload/model/multipart.dart";
|
import "package:photos/module/upload/model/multipart.dart";
|
||||||
import "package:photos/module/upload/model/xml.dart";
|
import "package:photos/module/upload/model/xml.dart";
|
||||||
import "package:photos/services/feature_flag_service.dart";
|
import "package:photos/services/feature_flag_service.dart";
|
||||||
@@ -24,6 +25,13 @@ class MultiPartUploader {
|
|||||||
this._featureFlagService,
|
this._featureFlagService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Future<EncryptionResult> getEncryptionResult(
|
||||||
|
String localId,
|
||||||
|
String fileHash,
|
||||||
|
) {
|
||||||
|
return _db.getFileEncryptionData(localId, fileHash);
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> calculatePartCount(int fileSize) async {
|
Future<int> calculatePartCount(int fileSize) async {
|
||||||
final partCount = (fileSize / multipartPartSizeForUpload).ceil();
|
final partCount = (fileSize / multipartPartSizeForUpload).ceil();
|
||||||
return partCount;
|
return partCount;
|
||||||
@@ -56,6 +64,7 @@ class MultiPartUploader {
|
|||||||
String encryptedFilePath,
|
String encryptedFilePath,
|
||||||
int fileSize,
|
int fileSize,
|
||||||
Uint8List fileKey,
|
Uint8List fileKey,
|
||||||
|
Uint8List fileNonce,
|
||||||
) async {
|
) async {
|
||||||
await _db.createTrackUploadsEntry(
|
await _db.createTrackUploadsEntry(
|
||||||
localId,
|
localId,
|
||||||
@@ -64,6 +73,7 @@ class MultiPartUploader {
|
|||||||
encryptedFilePath,
|
encryptedFilePath,
|
||||||
fileSize,
|
fileSize,
|
||||||
CryptoUtil.bin2base64(fileKey),
|
CryptoUtil.bin2base64(fileKey),
|
||||||
|
CryptoUtil.bin2base64(fileNonce),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,12 +128,17 @@ class MultiPartUploader {
|
|||||||
final partsLength = partsURLs.length;
|
final partsLength = partsURLs.length;
|
||||||
final etags = partInfo.partETags ?? <int, String>{};
|
final etags = partInfo.partETags ?? <int, String>{};
|
||||||
|
|
||||||
for (int i = 0; i < partsLength; i++) {
|
int i = 0;
|
||||||
if (i < (partUploadStatus?.length ?? 0) &&
|
final partSize = partInfo.partSize ?? multipartPartSizeForUpload;
|
||||||
(partUploadStatus?[i] ?? false)) {
|
|
||||||
continue;
|
// Go to the first part that is not uploaded
|
||||||
}
|
while (i < (partUploadStatus?.length ?? 0) &&
|
||||||
final partSize = partInfo.partSize ?? multipartPartSizeForUpload;
|
(partUploadStatus?[i] ?? false)) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start parts upload
|
||||||
|
while (i < partsLength) {
|
||||||
final partURL = partsURLs[i];
|
final partURL = partsURLs[i];
|
||||||
final isLastPart = i == partsLength - 1;
|
final isLastPart = i == partsLength - 1;
|
||||||
final fileSize =
|
final fileSize =
|
||||||
@@ -151,7 +166,9 @@ class MultiPartUploader {
|
|||||||
etags[i] = eTag!;
|
etags[i] = eTag!;
|
||||||
|
|
||||||
await _db.updatePartStatus(partInfo.urls.objectKey, i, eTag);
|
await _db.updatePartStatus(partInfo.urls.objectKey, i, eTag);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _db.updateTrackUploadStatus(
|
await _db.updateTrackUploadStatus(
|
||||||
partInfo.urls.objectKey,
|
partInfo.urls.objectKey,
|
||||||
MultipartStatus.uploaded,
|
MultipartStatus.uploaded,
|
||||||
|
@@ -2,7 +2,7 @@ import 'dart:async';
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
@@ -41,7 +41,6 @@ import 'package:photos/utils/file_uploader_util.dart';
|
|||||||
import "package:photos/utils/file_util.dart";
|
import "package:photos/utils/file_util.dart";
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
import "package:uuid/uuid.dart";
|
|
||||||
|
|
||||||
class FileUploader {
|
class FileUploader {
|
||||||
static const kMaximumConcurrentUploads = 4;
|
static const kMaximumConcurrentUploads = 4;
|
||||||
@@ -424,12 +423,19 @@ class FileUploader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final tempDirectory = Configuration.instance.getTempDirectory();
|
final tempDirectory = Configuration.instance.getTempDirectory();
|
||||||
final String uniqueID = const Uuid().v4().toString();
|
MediaUploadData? mediaUploadData;
|
||||||
|
mediaUploadData = await getUploadDataFromEnteFile(file);
|
||||||
|
|
||||||
|
final String uniqueID = lockKey +
|
||||||
|
"_" +
|
||||||
|
mediaUploadData.hashData!.fileHash!
|
||||||
|
.replaceAll('+', '')
|
||||||
|
.replaceAll('/', '');
|
||||||
|
|
||||||
final encryptedFilePath =
|
final encryptedFilePath =
|
||||||
'$tempDirectory$kUploadTempPrefix${uniqueID}_file.encrypted';
|
'$tempDirectory$kUploadTempPrefix${uniqueID}_file.encrypted';
|
||||||
final encryptedThumbnailPath =
|
final encryptedThumbnailPath =
|
||||||
'$tempDirectory$kUploadTempPrefix${uniqueID}_thumb.encrypted';
|
'$tempDirectory$kUploadTempPrefix${uniqueID}_thumb.encrypted';
|
||||||
MediaUploadData? mediaUploadData;
|
|
||||||
var uploadCompleted = false;
|
var uploadCompleted = false;
|
||||||
// This flag is used to decide whether to clear the iOS origin file cache
|
// This flag is used to decide whether to clear the iOS origin file cache
|
||||||
// or not.
|
// or not.
|
||||||
@@ -443,13 +449,25 @@ class FileUploader {
|
|||||||
'${isUpdatedFile ? 're-upload' : 'upload'} of ${file.toString()}',
|
'${isUpdatedFile ? 're-upload' : 'upload'} of ${file.toString()}',
|
||||||
);
|
);
|
||||||
|
|
||||||
mediaUploadData = await getUploadDataFromEnteFile(file);
|
var multipartEntryExists = mediaUploadData.hashData?.fileHash != null &&
|
||||||
|
await _uploadLocks.doesExists(
|
||||||
|
lockKey,
|
||||||
|
mediaUploadData.hashData!.fileHash!,
|
||||||
|
);
|
||||||
|
|
||||||
Uint8List? key;
|
Uint8List? key;
|
||||||
|
EncryptionResult? multipartEncryptionResult;
|
||||||
if (isUpdatedFile) {
|
if (isUpdatedFile) {
|
||||||
key = getFileKey(file);
|
key = getFileKey(file);
|
||||||
} else {
|
} else {
|
||||||
key = null;
|
multipartEncryptionResult = multipartEntryExists
|
||||||
|
? await _multiPartUploader.getEncryptionResult(
|
||||||
|
lockKey,
|
||||||
|
mediaUploadData.hashData!.fileHash!,
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
key = multipartEncryptionResult?.key;
|
||||||
|
|
||||||
// check if the file is already uploaded and can be mapped to existing
|
// check if the file is already uploaded and can be mapped to existing
|
||||||
// uploaded file. If map is found, it also returns the corresponding
|
// uploaded file. If map is found, it also returns the corresponding
|
||||||
// mapped or update file entry.
|
// mapped or update file entry.
|
||||||
@@ -468,16 +486,30 @@ class FileUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (File(encryptedFilePath).existsSync()) {
|
final encryptedFileExists = File(encryptedFilePath).existsSync();
|
||||||
|
|
||||||
|
// If the multipart entry exists but the encrypted file doesn't, it means
|
||||||
|
// that we'll have to reupload as the nonce is lost
|
||||||
|
if (multipartEntryExists) {
|
||||||
|
if (!encryptedFileExists) {
|
||||||
|
await _uploadLocks.deleteMultipartTrack(lockKey);
|
||||||
|
multipartEntryExists = false;
|
||||||
|
multipartEncryptionResult = null;
|
||||||
|
}
|
||||||
|
} else if (encryptedFileExists) {
|
||||||
|
// otherwise just delete the file for singlepart upload
|
||||||
await File(encryptedFilePath).delete();
|
await File(encryptedFilePath).delete();
|
||||||
}
|
}
|
||||||
await _checkIfWithinStorageLimit(mediaUploadData.sourceFile!);
|
await _checkIfWithinStorageLimit(mediaUploadData.sourceFile!);
|
||||||
final encryptedFile = File(encryptedFilePath);
|
final encryptedFile = File(encryptedFilePath);
|
||||||
final EncryptionResult fileAttributes = await CryptoUtil.encryptFile(
|
|
||||||
mediaUploadData.sourceFile!.path,
|
final EncryptionResult fileAttributes = multipartEncryptionResult ??
|
||||||
encryptedFilePath,
|
await CryptoUtil.encryptFile(
|
||||||
key: key,
|
mediaUploadData.sourceFile!.path,
|
||||||
);
|
encryptedFilePath,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
late final Uint8List? thumbnailData;
|
late final Uint8List? thumbnailData;
|
||||||
if (mediaUploadData.thumbnail == null &&
|
if (mediaUploadData.thumbnail == null &&
|
||||||
file.fileType == FileType.video) {
|
file.fileType == FileType.video) {
|
||||||
@@ -516,11 +548,7 @@ class FileUploader {
|
|||||||
final fileUploadURL = await _getUploadURL();
|
final fileUploadURL = await _getUploadURL();
|
||||||
fileObjectKey = await _putFile(fileUploadURL, encryptedFile);
|
fileObjectKey = await _putFile(fileUploadURL, encryptedFile);
|
||||||
} else {
|
} else {
|
||||||
if (mediaUploadData.hashData?.fileHash != null &&
|
if (multipartEntryExists) {
|
||||||
await _uploadLocks.doesExists(
|
|
||||||
lockKey,
|
|
||||||
mediaUploadData.hashData!.fileHash!,
|
|
||||||
)) {
|
|
||||||
fileObjectKey = await _multiPartUploader.putExistingMultipartFile(
|
fileObjectKey = await _multiPartUploader.putExistingMultipartFile(
|
||||||
encryptedFile,
|
encryptedFile,
|
||||||
lockKey,
|
lockKey,
|
||||||
@@ -536,6 +564,7 @@ class FileUploader {
|
|||||||
encryptedFilePath,
|
encryptedFilePath,
|
||||||
await encryptedFile.length(),
|
await encryptedFile.length(),
|
||||||
fileAttributes.key!,
|
fileAttributes.key!,
|
||||||
|
fileAttributes.header!,
|
||||||
);
|
);
|
||||||
fileObjectKey = await _multiPartUploader.putMultipartFile(
|
fileObjectKey = await _multiPartUploader.putMultipartFile(
|
||||||
fileUploadURLs,
|
fileUploadURLs,
|
||||||
@@ -546,7 +575,7 @@ class FileUploader {
|
|||||||
|
|
||||||
final metadata = await file.getMetadataForUpload(mediaUploadData);
|
final metadata = await file.getMetadataForUpload(mediaUploadData);
|
||||||
final encryptedMetadataResult = await CryptoUtil.encryptChaCha(
|
final encryptedMetadataResult = await CryptoUtil.encryptChaCha(
|
||||||
utf8.encode(jsonEncode(metadata)) as Uint8List,
|
utf8.encode(jsonEncode(metadata)),
|
||||||
fileAttributes.key!,
|
fileAttributes.key!,
|
||||||
);
|
);
|
||||||
final fileDecryptionHeader =
|
final fileDecryptionHeader =
|
||||||
@@ -628,7 +657,7 @@ class FileUploader {
|
|||||||
}
|
}
|
||||||
await FilesDB.instance.update(remoteFile);
|
await FilesDB.instance.update(remoteFile);
|
||||||
}
|
}
|
||||||
await UploadLocksDB.instance.deleteCompletedRecord(lockKey);
|
await UploadLocksDB.instance.deleteMultipartTrack(lockKey);
|
||||||
|
|
||||||
if (!_isBackground) {
|
if (!_isBackground) {
|
||||||
Bus.instance.fire(
|
Bus.instance.fire(
|
||||||
@@ -1051,7 +1080,7 @@ class FileUploader {
|
|||||||
if (_uploadURLs.isEmpty) {
|
if (_uploadURLs.isEmpty) {
|
||||||
// the queue is empty, fetch at least for one file to handle force uploads
|
// the queue is empty, fetch at least for one file to handle force uploads
|
||||||
// that are not in the queue. This is to also avoid
|
// that are not in the queue. This is to also avoid
|
||||||
await fetchUploadURLs(max(_queue.length, 1));
|
await fetchUploadURLs(math.max(_queue.length, 1));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return _uploadURLs.removeFirst();
|
return _uploadURLs.removeFirst();
|
||||||
@@ -1073,7 +1102,7 @@ class FileUploader {
|
|||||||
final response = await _enteDio.get(
|
final response = await _enteDio.get(
|
||||||
"/files/upload-urls",
|
"/files/upload-urls",
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
"count": min(42, fileCount * 2), // m4gic number
|
"count": math.min(42, fileCount * 2), // m4gic number
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
final urls = (response.data["urls"] as List)
|
final urls = (response.data["urls"] as List)
|
||||||
|
Reference in New Issue
Block a user