Implement ability to update files on remote
This commit is contained in:
parent
51f083d290
commit
d318a57d23
3 changed files with 167 additions and 11 deletions
|
@ -273,6 +273,79 @@ class FilesDB {
|
|||
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(
|
||||
List<int> collectionIDs) async {
|
||||
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 {
|
||||
final db = await instance.database;
|
||||
final values = new Map<String, dynamic>();
|
||||
|
@ -573,6 +656,37 @@ class FilesDB {
|
|||
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) {
|
||||
final file = File();
|
||||
file.generatedID = row[columnGeneratedID];
|
||||
|
|
|
@ -30,6 +30,7 @@ class SyncService {
|
|||
final _uploader = FileUploader.instance;
|
||||
final _collectionsService = CollectionsService.instance;
|
||||
final _downloader = DiffFetcher();
|
||||
final _uploadedLocalFileIDs = Set<String>();
|
||||
bool _isSyncInProgress = false;
|
||||
bool _syncStopRequested = false;
|
||||
Future<void> _existingSync;
|
||||
|
@ -67,6 +68,7 @@ class SyncService {
|
|||
}
|
||||
|
||||
Future<void> sync() async {
|
||||
_uploadedLocalFileIDs.addAll(await _db.getUploadedLocalFileIDs());
|
||||
_syncStopRequested = false;
|
||||
if (_isSyncInProgress) {
|
||||
_logger.warning("Sync already in progress, skipping.");
|
||||
|
@ -147,7 +149,20 @@ class SyncService {
|
|||
final files = await getDeviceFiles(fromTime, toTime);
|
||||
if (files.isNotEmpty) {
|
||||
_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);
|
||||
_logger.info("Inserted " + files.length.toString() + " files.");
|
||||
await _prefs.setInt(_dbUpdationTimeKey, toTime);
|
||||
|
@ -201,30 +216,53 @@ class SyncService {
|
|||
|
||||
Future<void> _uploadDiff() async {
|
||||
final foldersToBackUp = Configuration.instance.getPathsToBackUp();
|
||||
List<File> filesToBeUploaded =
|
||||
final filesToBeUploaded =
|
||||
await _db.getFilesToBeUploadedWithinFolders(foldersToBackUp);
|
||||
if (kDebugMode) {
|
||||
filesToBeUploaded = filesToBeUploaded
|
||||
.where((element) => element.fileType != FileType.video)
|
||||
.toList();
|
||||
filesToBeUploaded
|
||||
.removeWhere((element) => element.fileType == FileType.video);
|
||||
}
|
||||
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) {
|
||||
_syncStopRequested = false;
|
||||
Bus.instance
|
||||
.fire(SyncStatusUpdate(SyncStatus.completed, wasStopped: true));
|
||||
return;
|
||||
}
|
||||
File file = filesToBeUploaded[i];
|
||||
final collectionID = (await CollectionsService.instance
|
||||
.getOrCreateForPath(file.deviceFolder))
|
||||
.id;
|
||||
final future = _uploader.upload(file, collectionID).then((value) {
|
||||
uploadCounter++;
|
||||
Bus.instance
|
||||
.fire(CollectionUpdatedEvent(collectionID: file.collectionID));
|
||||
Bus.instance.fire(SyncStatusUpdate(SyncStatus.in_progress,
|
||||
completed: i + 1, total: filesToBeUploaded.length));
|
||||
completed: uploadCounter, total: totalUploads));
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
|
|
|
@ -125,7 +125,6 @@ class FileUploader {
|
|||
_currentlyUploading++;
|
||||
try {
|
||||
final uploadedFile = await _tryToUpload(file, collectionID, forcedUpload);
|
||||
await FilesDB.instance.update(uploadedFile);
|
||||
_queue.remove(file.generatedID).completer.complete(uploadedFile);
|
||||
} catch (e) {
|
||||
_queue.remove(file.generatedID).completer.completeError(e);
|
||||
|
@ -222,7 +221,7 @@ class FileUploader {
|
|||
final metadataDecryptionHeader =
|
||||
Sodium.bin2base64(encryptedMetadataData.header);
|
||||
if (isAlreadyUploadedFile) {
|
||||
return await _updateFile(
|
||||
final updatedFile = await _updateFile(
|
||||
file,
|
||||
fileObjectKey,
|
||||
fileDecryptionHeader,
|
||||
|
@ -231,8 +230,11 @@ class FileUploader {
|
|||
encryptedMetadata,
|
||||
metadataDecryptionHeader,
|
||||
);
|
||||
// Update across all collections
|
||||
await FilesDB.instance.updateUploadedFileAcrossCollections(updatedFile);
|
||||
return updatedFile;
|
||||
} else {
|
||||
return await _uploadFile(
|
||||
final uploadedFile = await _uploadFile(
|
||||
file,
|
||||
collectionID,
|
||||
fileAttributes,
|
||||
|
@ -243,6 +245,8 @@ class FileUploader {
|
|||
encryptedMetadata,
|
||||
metadataDecryptionHeader,
|
||||
);
|
||||
await FilesDB.instance.update(uploadedFile);
|
||||
return uploadedFile;
|
||||
}
|
||||
} catch (e, s) {
|
||||
_logger.severe(
|
||||
|
|
Loading…
Add table
Reference in a new issue