浏览代码

Implement ability to update files on remote

Vishnu Mohandas 4 年之前
父节点
当前提交
d318a57d23
共有 3 个文件被更改,包括 167 次插入11 次删除
  1. 114 0
      lib/db/files_db.dart
  2. 46 8
      lib/services/sync_service.dart
  3. 7 3
      lib/utils/file_uploader.dart

+ 114 - 0
lib/db/files_db.dart

@@ -273,6 +273,79 @@ class FilesDB {
     return _convertToFiles(results);
     return _convertToFiles(results);
   }
   }
 
 
+  Future<List<int>> getUploadedFileIDsToBeUpdated() async {
+    final db = await instance.database;
+    final rows = await db.query(
+      table,
+      columns: [columnUploadedFileID],
+      where:
+          '($columnUploadedFileID IS NOT NULL AND $columnUpdationTime IS NULL AND $columnIsDeleted = 0)',
+      orderBy: '$columnCreationTime DESC',
+      distinct: true,
+    );
+    final uploadedFileIDs = List<int>();
+    for (final row in rows) {
+      uploadedFileIDs.add(row[columnUploadedFileID]);
+    }
+    return uploadedFileIDs;
+  }
+
+  Future<File> getUploadedFileInAnyCollection(int uploadedFileID) async {
+    final db = await instance.database;
+    final results = await db.query(
+      table,
+      where: '$columnUploadedFileID = ?',
+      whereArgs: [
+        uploadedFileID,
+      ],
+      limit: 1,
+    );
+    if (results.isEmpty) {
+      return null;
+    }
+    return _convertToFiles(results)[0];
+  }
+
+  Future<Set<String>> getUploadedLocalFileIDs() async {
+    final db = await instance.database;
+    final rows = await db.query(
+      table,
+      columns: [columnLocalID],
+      distinct: true,
+      where:
+          '$columnLocalID IS NOT NULL AND $columnUploadedFileID IS NOT NULL AND $columnIsDeleted = 0',
+    );
+    final result = Set<String>();
+    for (final row in rows) {
+      result.add(row[columnLocalID]);
+    }
+    return result;
+  }
+
+  Future<int> updateUploadedFile(
+    String localID,
+    String title,
+    Location location,
+    int creationTime,
+    int modificationTime,
+    int updationTime,
+  ) async {
+    final db = await instance.database;
+    return await db.update(
+      table,
+      {
+        columnTitle: title,
+        columnLatitude: location.latitude,
+        columnLongitude: location.longitude,
+        columnCreationTime: creationTime,
+        columnModificationTime: modificationTime,
+        columnUpdationTime: updationTime,
+      },
+      where: '$columnLocalID = ?',
+      whereArgs: [localID],
+    );
+  }
+
   Future<Map<int, File>> getLastCreatedFilesInCollections(
   Future<Map<int, File>> getLastCreatedFilesInCollections(
       List<int> collectionIDs) async {
       List<int> collectionIDs) async {
     final db = await instance.database;
     final db = await instance.database;
@@ -398,6 +471,16 @@ class FilesDB {
     );
     );
   }
   }
 
 
+  Future<int> updateUploadedFileAcrossCollections(File file) async {
+    final db = await instance.database;
+    return await db.update(
+      table,
+      _getRowForFileWithoutCollection(file),
+      where: '$columnUploadedFileID = ?',
+      whereArgs: [file.uploadedFileID],
+    );
+  }
+
   Future<int> markForDeletion(int uploadedFileID) async {
   Future<int> markForDeletion(int uploadedFileID) async {
     final db = await instance.database;
     final db = await instance.database;
     final values = new Map<String, dynamic>();
     final values = new Map<String, dynamic>();
@@ -573,6 +656,37 @@ class FilesDB {
     return row;
     return row;
   }
   }
 
 
+  Map<String, dynamic> _getRowForFileWithoutCollection(File file) {
+    final row = new Map<String, dynamic>();
+    row[columnLocalID] = file.localID;
+    row[columnUploadedFileID] = file.uploadedFileID;
+    row[columnOwnerID] = file.ownerID;
+    row[columnTitle] = file.title;
+    row[columnDeviceFolder] = file.deviceFolder;
+    if (file.location != null) {
+      row[columnLatitude] = file.location.latitude;
+      row[columnLongitude] = file.location.longitude;
+    }
+    switch (file.fileType) {
+      case FileType.image:
+        row[columnFileType] = 0;
+        break;
+      case FileType.video:
+        row[columnFileType] = 1;
+        break;
+      default:
+        row[columnFileType] = -1;
+    }
+    row[columnIsEncrypted] = file.isEncrypted ? 1 : 0;
+    row[columnCreationTime] = file.creationTime;
+    row[columnModificationTime] = file.modificationTime;
+    row[columnUpdationTime] = file.updationTime;
+    row[columnFileDecryptionHeader] = file.fileDecryptionHeader;
+    row[columnThumbnailDecryptionHeader] = file.thumbnailDecryptionHeader;
+    row[columnMetadataDecryptionHeader] = file.metadataDecryptionHeader;
+    return row;
+  }
+
   File _getFileFromRow(Map<String, dynamic> row) {
   File _getFileFromRow(Map<String, dynamic> row) {
     final file = File();
     final file = File();
     file.generatedID = row[columnGeneratedID];
     file.generatedID = row[columnGeneratedID];

+ 46 - 8
lib/services/sync_service.dart

@@ -30,6 +30,7 @@ class SyncService {
   final _uploader = FileUploader.instance;
   final _uploader = FileUploader.instance;
   final _collectionsService = CollectionsService.instance;
   final _collectionsService = CollectionsService.instance;
   final _downloader = DiffFetcher();
   final _downloader = DiffFetcher();
+  final _uploadedLocalFileIDs = Set<String>();
   bool _isSyncInProgress = false;
   bool _isSyncInProgress = false;
   bool _syncStopRequested = false;
   bool _syncStopRequested = false;
   Future<void> _existingSync;
   Future<void> _existingSync;
@@ -67,6 +68,7 @@ class SyncService {
   }
   }
 
 
   Future<void> sync() async {
   Future<void> sync() async {
+    _uploadedLocalFileIDs.addAll(await _db.getUploadedLocalFileIDs());
     _syncStopRequested = false;
     _syncStopRequested = false;
     if (_isSyncInProgress) {
     if (_isSyncInProgress) {
       _logger.warning("Sync already in progress, skipping.");
       _logger.warning("Sync already in progress, skipping.");
@@ -147,7 +149,20 @@ class SyncService {
     final files = await getDeviceFiles(fromTime, toTime);
     final files = await getDeviceFiles(fromTime, toTime);
     if (files.isNotEmpty) {
     if (files.isNotEmpty) {
       _logger.info("Fetched " + files.length.toString() + " files.");
       _logger.info("Fetched " + files.length.toString() + " files.");
-      // Deal with file updates
+      final updatedFiles =
+          files.where((file) => _uploadedLocalFileIDs.contains(file.localID));
+      _logger.info(updatedFiles.length.toString() + " files were updated.");
+      for (final file in updatedFiles) {
+        await _db.updateUploadedFile(
+          file.localID,
+          file.title,
+          file.location,
+          file.creationTime,
+          file.modificationTime,
+          null,
+        );
+      }
+      files.removeWhere((file) => _uploadedLocalFileIDs.contains(file.localID));
       await _db.insertMultiple(files);
       await _db.insertMultiple(files);
       _logger.info("Inserted " + files.length.toString() + " files.");
       _logger.info("Inserted " + files.length.toString() + " files.");
       await _prefs.setInt(_dbUpdationTimeKey, toTime);
       await _prefs.setInt(_dbUpdationTimeKey, toTime);
@@ -201,30 +216,53 @@ class SyncService {
 
 
   Future<void> _uploadDiff() async {
   Future<void> _uploadDiff() async {
     final foldersToBackUp = Configuration.instance.getPathsToBackUp();
     final foldersToBackUp = Configuration.instance.getPathsToBackUp();
-    List<File> filesToBeUploaded =
+    final filesToBeUploaded =
         await _db.getFilesToBeUploadedWithinFolders(foldersToBackUp);
         await _db.getFilesToBeUploadedWithinFolders(foldersToBackUp);
     if (kDebugMode) {
     if (kDebugMode) {
-      filesToBeUploaded = filesToBeUploaded
-          .where((element) => element.fileType != FileType.video)
-          .toList();
+      filesToBeUploaded
+          .removeWhere((element) => element.fileType == FileType.video);
     }
     }
     final futures = List<Future>();
     final futures = List<Future>();
-    for (int i = 0; i < filesToBeUploaded.length; i++) {
+
+    final updatedFileIDs = await _db.getUploadedFileIDsToBeUpdated();
+
+    int uploadCounter = 0;
+    final totalUploads = filesToBeUploaded.length + updatedFileIDs.length;
+
+    for (final uploadedFileID in updatedFileIDs) {
+      if (_syncStopRequested) {
+        _syncStopRequested = false;
+        Bus.instance
+            .fire(SyncStatusUpdate(SyncStatus.completed, wasStopped: true));
+        return;
+      }
+      final file = await _db.getUploadedFileInAnyCollection(uploadedFileID);
+      final future = _uploader.upload(file, file.collectionID).then((value) {
+        uploadCounter++;
+        Bus.instance
+            .fire(CollectionUpdatedEvent(collectionID: file.collectionID));
+        Bus.instance.fire(SyncStatusUpdate(SyncStatus.in_progress,
+            completed: uploadCounter, total: totalUploads));
+      });
+      futures.add(future);
+    }
+
+    for (final file in filesToBeUploaded) {
       if (_syncStopRequested) {
       if (_syncStopRequested) {
         _syncStopRequested = false;
         _syncStopRequested = false;
         Bus.instance
         Bus.instance
             .fire(SyncStatusUpdate(SyncStatus.completed, wasStopped: true));
             .fire(SyncStatusUpdate(SyncStatus.completed, wasStopped: true));
         return;
         return;
       }
       }
-      File file = filesToBeUploaded[i];
       final collectionID = (await CollectionsService.instance
       final collectionID = (await CollectionsService.instance
               .getOrCreateForPath(file.deviceFolder))
               .getOrCreateForPath(file.deviceFolder))
           .id;
           .id;
       final future = _uploader.upload(file, collectionID).then((value) {
       final future = _uploader.upload(file, collectionID).then((value) {
+        uploadCounter++;
         Bus.instance
         Bus.instance
             .fire(CollectionUpdatedEvent(collectionID: file.collectionID));
             .fire(CollectionUpdatedEvent(collectionID: file.collectionID));
         Bus.instance.fire(SyncStatusUpdate(SyncStatus.in_progress,
         Bus.instance.fire(SyncStatusUpdate(SyncStatus.in_progress,
-            completed: i + 1, total: filesToBeUploaded.length));
+            completed: uploadCounter, total: totalUploads));
       });
       });
       futures.add(future);
       futures.add(future);
     }
     }

+ 7 - 3
lib/utils/file_uploader.dart

@@ -125,7 +125,6 @@ class FileUploader {
     _currentlyUploading++;
     _currentlyUploading++;
     try {
     try {
       final uploadedFile = await _tryToUpload(file, collectionID, forcedUpload);
       final uploadedFile = await _tryToUpload(file, collectionID, forcedUpload);
-      await FilesDB.instance.update(uploadedFile);
       _queue.remove(file.generatedID).completer.complete(uploadedFile);
       _queue.remove(file.generatedID).completer.complete(uploadedFile);
     } catch (e) {
     } catch (e) {
       _queue.remove(file.generatedID).completer.completeError(e);
       _queue.remove(file.generatedID).completer.completeError(e);
@@ -222,7 +221,7 @@ class FileUploader {
       final metadataDecryptionHeader =
       final metadataDecryptionHeader =
           Sodium.bin2base64(encryptedMetadataData.header);
           Sodium.bin2base64(encryptedMetadataData.header);
       if (isAlreadyUploadedFile) {
       if (isAlreadyUploadedFile) {
-        return await _updateFile(
+        final updatedFile = await _updateFile(
           file,
           file,
           fileObjectKey,
           fileObjectKey,
           fileDecryptionHeader,
           fileDecryptionHeader,
@@ -231,8 +230,11 @@ class FileUploader {
           encryptedMetadata,
           encryptedMetadata,
           metadataDecryptionHeader,
           metadataDecryptionHeader,
         );
         );
+        // Update across all collections
+        await FilesDB.instance.updateUploadedFileAcrossCollections(updatedFile);
+        return updatedFile;
       } else {
       } else {
-        return await _uploadFile(
+        final uploadedFile = await _uploadFile(
           file,
           file,
           collectionID,
           collectionID,
           fileAttributes,
           fileAttributes,
@@ -243,6 +245,8 @@ class FileUploader {
           encryptedMetadata,
           encryptedMetadata,
           metadataDecryptionHeader,
           metadataDecryptionHeader,
         );
         );
+        await FilesDB.instance.update(uploadedFile);
+        return uploadedFile;
       }
       }
     } catch (e, s) {
     } catch (e, s) {
       _logger.severe(
       _logger.severe(