Browse Source

Perform local storage check before upload

Neeraj Gupta 2 years ago
parent
commit
e2da09bc22
1 changed files with 33 additions and 1 deletions
  1. 33 1
      lib/utils/file_uploader.dart

+ 33 - 1
lib/utils/file_uploader.dart

@@ -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(