|
@@ -24,12 +24,13 @@ import 'package:photos/models/encryption_result.dart';
|
|
|
import 'package:photos/models/file.dart';
|
|
|
import 'package:photos/models/file_type.dart';
|
|
|
import "package:photos/models/metadata/file_magic.dart";
|
|
|
-
|
|
|
import 'package:photos/models/upload_url.dart';
|
|
|
+import "package:photos/models/user_details.dart";
|
|
|
import 'package:photos/services/collections_service.dart';
|
|
|
import "package:photos/services/file_magic_service.dart";
|
|
|
import 'package:photos/services/local_sync_service.dart';
|
|
|
import 'package:photos/services/sync_service.dart';
|
|
|
+import "package:photos/services/user_service.dart";
|
|
|
import 'package:photos/utils/crypto_util.dart';
|
|
|
import 'package:photos/utils/file_download_util.dart';
|
|
|
import 'package:photos/utils/file_uploader_util.dart';
|
|
@@ -43,6 +44,7 @@ class FileUploader {
|
|
|
static const kMaximumUploadAttempts = 4;
|
|
|
static const kBlockedUploadsPollFrequency = Duration(seconds: 2);
|
|
|
static const kFileUploadTimeout = Duration(minutes: 50);
|
|
|
+ static const k20MBStorageBuffer = 20 * 1024 * 1024;
|
|
|
|
|
|
final _logger = Logger("FileUploader");
|
|
|
final _dio = NetworkClient.instance.getDio();
|
|
@@ -391,6 +393,7 @@ class FileUploader {
|
|
|
if (io.File(encryptedFilePath).existsSync()) {
|
|
|
await io.File(encryptedFilePath).delete();
|
|
|
}
|
|
|
+ await _checkIfWithinStorageLimit(mediaUploadData!.sourceFile!);
|
|
|
final encryptedFile = io.File(encryptedFilePath);
|
|
|
final EncryptionResult fileAttributes = await CryptoUtil.encryptFile(
|
|
|
mediaUploadData!.sourceFile!.path,
|
|
@@ -692,6 +695,35 @@ class FileUploader {
|
|
|
await _uploadLocks.releaseLock(lockKey, _processType.toString());
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ _checkIfWithinStorageLimit verifies if the file size for encryption and upload
|
|
|
+ is within the storage limit. It throws StorageLimitExceededError if the limit
|
|
|
+ is exceeded. This check is best effort and may not be completely accurate
|
|
|
+ due to UserDetail cache. It prevents infinite loops when clients attempt to
|
|
|
+ upload files that exceed the server's storage limit + buffer.
|
|
|
+ Note: Local storageBuffer is 20MB, server storageBuffer is 50MB, and an
|
|
|
+ additional 30MB is reserved for thumbnails and encryption overhead.
|
|
|
+ */
|
|
|
+ Future<void> _checkIfWithinStorageLimit(io.File fileToBeUploaded) async {
|
|
|
+ try {
|
|
|
+ final UserDetails? userDetails =
|
|
|
+ UserService.instance.getCachedUserDetails();
|
|
|
+ if (userDetails == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // add 5MB to the free storage
|
|
|
+ final num freeStorage = userDetails.getFreeStorage() + k20MBStorageBuffer;
|
|
|
+ final num fileSize = await fileToBeUploaded.length();
|
|
|
+ if (fileSize > freeStorage) {
|
|
|
+ _logger.warning('Storage limit exceeded fileSize $fileSize and '
|
|
|
+ 'freeStorage $freeStorage');
|
|
|
+ throw StorageLimitExceededError();
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ _logger.severe('Error checking storage limit', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Future _onInvalidFileError(File file, InvalidFileError e) async {
|
|
|
final String ext = file.title == null ? "no title" : extension(file.title!);
|
|
|
_logger.severe(
|