diff_fetcher.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import 'dart:convert';
  2. import 'package:dio/dio.dart';
  3. import 'package:flutter_sodium/flutter_sodium.dart';
  4. import 'package:logging/logging.dart';
  5. import 'package:photos/core/configuration.dart';
  6. import 'package:photos/core/event_bus.dart';
  7. import 'package:photos/core/network.dart';
  8. import 'package:photos/db/files_db.dart';
  9. import 'package:photos/events/collection_updated_event.dart';
  10. import 'package:photos/events/local_photos_updated_event.dart';
  11. import 'package:photos/events/remote_sync_event.dart';
  12. import 'package:photos/models/file.dart';
  13. import 'package:photos/utils/crypto_util.dart';
  14. import 'package:photos/utils/file_download_util.dart';
  15. class DiffFetcher {
  16. final _logger = Logger("DiffFetcher");
  17. final _dio = Network.instance.getDio();
  18. Future<Diff> getEncryptedFilesDiff(
  19. int collectionID, int sinceTime, int limit) async {
  20. return _dio
  21. .get(
  22. Configuration.instance.getHttpEndpoint() + "/collections/diff",
  23. options: Options(
  24. headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  25. queryParameters: {
  26. "collectionID": collectionID,
  27. "sinceTime": sinceTime,
  28. "limit": limit,
  29. },
  30. )
  31. .catchError((e) => _logger.severe(e))
  32. .then((response) async {
  33. final files = List<File>();
  34. if (response != null) {
  35. Bus.instance.fire(RemoteSyncEvent(true));
  36. final diff = response.data["diff"] as List;
  37. final startTime = DateTime.now();
  38. final existingFiles =
  39. await FilesDB.instance.getUploadedFileIDs(collectionID);
  40. for (final item in diff) {
  41. final file = File();
  42. file.uploadedFileID = item["id"];
  43. file.collectionID = item["collectionID"];
  44. if (item["isDeleted"]) {
  45. if (existingFiles.contains(file.uploadedFileID)) {
  46. await FilesDB.instance.deleteFromCollection(
  47. file.uploadedFileID, file.collectionID);
  48. Bus.instance.fire(
  49. CollectionUpdatedEvent(file.collectionID, [file]));
  50. Bus.instance.fire(LocalPhotosUpdatedEvent([file]));
  51. }
  52. continue;
  53. }
  54. file.updationTime = item["updationTime"];
  55. if (existingFiles.contains(file.uploadedFileID)) {
  56. final existingFile = await FilesDB.instance
  57. .getUploadedFile(file.uploadedFileID, file.collectionID);
  58. if (existingFile != null &&
  59. existingFile.updationTime == file.updationTime) {
  60. continue;
  61. }
  62. }
  63. file.ownerID = item["ownerID"];
  64. file.encryptedKey = item["encryptedKey"];
  65. file.keyDecryptionNonce = item["keyDecryptionNonce"];
  66. file.fileDecryptionHeader = item["file"]["decryptionHeader"];
  67. file.thumbnailDecryptionHeader =
  68. item["thumbnail"]["decryptionHeader"];
  69. file.metadataDecryptionHeader =
  70. item["metadata"]["decryptionHeader"];
  71. final encodedMetadata = await CryptoUtil.decryptChaCha(
  72. Sodium.base642bin(item["metadata"]["encryptedData"]),
  73. decryptFileKey(file),
  74. Sodium.base642bin(file.metadataDecryptionHeader),
  75. );
  76. Map<String, dynamic> metadata =
  77. jsonDecode(utf8.decode(encodedMetadata));
  78. file.applyMetadata(metadata);
  79. files.add(file);
  80. }
  81. final endTime = DateTime.now();
  82. _logger.info("time for parsing " +
  83. files.length.toString() +
  84. ": " +
  85. Duration(
  86. microseconds: (endTime.microsecondsSinceEpoch -
  87. startTime.microsecondsSinceEpoch))
  88. .inMilliseconds
  89. .toString());
  90. return Diff(files, diff.length);
  91. } else {
  92. Bus.instance.fire(RemoteSyncEvent(false));
  93. return Diff(List<File>(), 0);
  94. }
  95. });
  96. }
  97. }
  98. class Diff {
  99. final List<File> updatedFiles;
  100. final int fetchCount;
  101. Diff(this.updatedFiles, this.fetchCount);
  102. }