diff_fetcher.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import 'dart:convert';
  2. import 'dart:math';
  3. import 'package:logging/logging.dart';
  4. import 'package:photos/core/network/network.dart';
  5. import 'package:photos/db/files_db.dart';
  6. import 'package:photos/models/file/file.dart';
  7. import "package:photos/models/metadata/file_magic.dart";
  8. import 'package:photos/utils/crypto_util.dart';
  9. import 'package:photos/utils/file_download_util.dart';
  10. class DiffFetcher {
  11. final _logger = Logger("DiffFetcher");
  12. final _enteDio = NetworkClient.instance.enteDio;
  13. Future<Diff> getEncryptedFilesDiff(int collectionID, int sinceTime) async {
  14. try {
  15. final response = await _enteDio.get(
  16. "/collections/v2/diff",
  17. queryParameters: {
  18. "collectionID": collectionID,
  19. "sinceTime": sinceTime,
  20. },
  21. );
  22. int latestUpdatedAtTime = 0;
  23. final diff = response.data["diff"] as List;
  24. final bool hasMore = response.data["hasMore"] as bool;
  25. final startTime = DateTime.now();
  26. late Set<int> existingUploadIDs;
  27. if (diff.isNotEmpty) {
  28. existingUploadIDs =
  29. await FilesDB.instance.getUploadedFileIDs(collectionID);
  30. }
  31. final deletedFiles = <EnteFile>[];
  32. final updatedFiles = <EnteFile>[];
  33. for (final item in diff) {
  34. final file = EnteFile();
  35. file.uploadedFileID = item["id"];
  36. file.collectionID = item["collectionID"];
  37. file.updationTime = item["updationTime"];
  38. latestUpdatedAtTime = max(latestUpdatedAtTime, file.updationTime!);
  39. if (item["isDeleted"]) {
  40. if (existingUploadIDs.contains(file.uploadedFileID)) {
  41. deletedFiles.add(file);
  42. }
  43. continue;
  44. }
  45. if (existingUploadIDs.contains(file.uploadedFileID)) {
  46. final existingFile = await FilesDB.instance
  47. .getUploadedFile(file.uploadedFileID!, file.collectionID!);
  48. if (existingFile != null) {
  49. file.generatedID = existingFile.generatedID;
  50. file.addedTime = existingFile.addedTime;
  51. }
  52. }
  53. file.ownerID = item["ownerID"];
  54. file.encryptedKey = item["encryptedKey"];
  55. file.keyDecryptionNonce = item["keyDecryptionNonce"];
  56. file.fileDecryptionHeader = item["file"]["decryptionHeader"];
  57. file.thumbnailDecryptionHeader = item["thumbnail"]["decryptionHeader"];
  58. file.metadataDecryptionHeader = item["metadata"]["decryptionHeader"];
  59. if (item["info"] != null) {
  60. file.fileSize = item["info"]["fileSize"];
  61. }
  62. final fileKey = getFileKey(file);
  63. final encodedMetadata = await CryptoUtil.decryptChaCha(
  64. CryptoUtil.base642bin(item["metadata"]["encryptedData"]),
  65. fileKey,
  66. CryptoUtil.base642bin(file.metadataDecryptionHeader!),
  67. );
  68. final Map<String, dynamic> metadata =
  69. jsonDecode(utf8.decode(encodedMetadata));
  70. file.applyMetadata(metadata);
  71. if (item['magicMetadata'] != null) {
  72. final utfEncodedMmd = await CryptoUtil.decryptChaCha(
  73. CryptoUtil.base642bin(item['magicMetadata']['data']),
  74. fileKey,
  75. CryptoUtil.base642bin(item['magicMetadata']['header']),
  76. );
  77. file.mMdEncodedJson = utf8.decode(utfEncodedMmd);
  78. file.mMdVersion = item['magicMetadata']['version'];
  79. file.magicMetadata =
  80. MagicMetadata.fromEncodedJson(file.mMdEncodedJson!);
  81. }
  82. if (item['pubMagicMetadata'] != null) {
  83. final utfEncodedMmd = await CryptoUtil.decryptChaCha(
  84. CryptoUtil.base642bin(item['pubMagicMetadata']['data']),
  85. fileKey,
  86. CryptoUtil.base642bin(item['pubMagicMetadata']['header']),
  87. );
  88. file.pubMmdEncodedJson = utf8.decode(utfEncodedMmd);
  89. file.pubMmdVersion = item['pubMagicMetadata']['version'];
  90. file.pubMagicMetadata =
  91. PubMagicMetadata.fromEncodedJson(file.pubMmdEncodedJson!);
  92. }
  93. updatedFiles.add(file);
  94. }
  95. _logger.info('[Collection-$collectionID] parsed ${diff.length} '
  96. 'diff items ( ${updatedFiles.length} updated) in ${DateTime.now().difference(startTime).inMilliseconds}ms');
  97. return Diff(updatedFiles, deletedFiles, hasMore, latestUpdatedAtTime);
  98. } catch (e, s) {
  99. _logger.severe(e, s);
  100. rethrow;
  101. }
  102. }
  103. }
  104. class Diff {
  105. final List<EnteFile> updatedFiles;
  106. final List<EnteFile> deletedFiles;
  107. final bool hasMore;
  108. final int latestUpdatedAtTime;
  109. Diff(
  110. this.updatedFiles,
  111. this.deletedFiles,
  112. this.hasMore,
  113. this.latestUpdatedAtTime,
  114. );
  115. }