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.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 = await FilesDB.instance.getUploadedFileIDs(collectionID);
  29. }
  30. final deletedFiles = <File>[];
  31. final updatedFiles = <File>[];
  32. for (final item in diff) {
  33. final file = File();
  34. file.uploadedFileID = item["id"];
  35. file.collectionID = item["collectionID"];
  36. file.updationTime = item["updationTime"];
  37. latestUpdatedAtTime = max(latestUpdatedAtTime, file.updationTime!);
  38. if (item["isDeleted"]) {
  39. if (existingUploadIDs.contains(file.uploadedFileID)) {
  40. deletedFiles.add(file);
  41. }
  42. continue;
  43. }
  44. if (existingUploadIDs.contains(file.uploadedFileID)) {
  45. final existingFile = await FilesDB.instance
  46. .getUploadedFile(file.uploadedFileID!, file.collectionID!);
  47. if (existingFile != null) {
  48. file.generatedID = existingFile.generatedID;
  49. file.addedTime = existingFile.addedTime;
  50. }
  51. }
  52. file.ownerID = item["ownerID"];
  53. file.encryptedKey = item["encryptedKey"];
  54. file.keyDecryptionNonce = item["keyDecryptionNonce"];
  55. file.fileDecryptionHeader = item["file"]["decryptionHeader"];
  56. file.thumbnailDecryptionHeader = item["thumbnail"]["decryptionHeader"];
  57. file.metadataDecryptionHeader = item["metadata"]["decryptionHeader"];
  58. if (item["info"] != null) {
  59. file.fileSize = item["info"]["fileSize"];
  60. }
  61. final fileKey = getFileKey(file);
  62. final encodedMetadata = await CryptoUtil.decryptChaCha(
  63. CryptoUtil.base642bin(item["metadata"]["encryptedData"]),
  64. fileKey,
  65. CryptoUtil.base642bin(file.metadataDecryptionHeader!),
  66. );
  67. final Map<String, dynamic> metadata =
  68. jsonDecode(utf8.decode(encodedMetadata));
  69. file.applyMetadata(metadata);
  70. if (item['magicMetadata'] != null) {
  71. final utfEncodedMmd = await CryptoUtil.decryptChaCha(
  72. CryptoUtil.base642bin(item['magicMetadata']['data']),
  73. fileKey,
  74. CryptoUtil.base642bin(item['magicMetadata']['header']),
  75. );
  76. file.mMdEncodedJson = utf8.decode(utfEncodedMmd);
  77. file.mMdVersion = item['magicMetadata']['version'];
  78. file.magicMetadata =
  79. MagicMetadata.fromEncodedJson(file.mMdEncodedJson!);
  80. }
  81. if (item['pubMagicMetadata'] != null) {
  82. final utfEncodedMmd = await CryptoUtil.decryptChaCha(
  83. CryptoUtil.base642bin(item['pubMagicMetadata']['data']),
  84. fileKey,
  85. CryptoUtil.base642bin(item['pubMagicMetadata']['header']),
  86. );
  87. file.pubMmdEncodedJson = utf8.decode(utfEncodedMmd);
  88. file.pubMmdVersion = item['pubMagicMetadata']['version'];
  89. file.pubMagicMetadata =
  90. PubMagicMetadata.fromEncodedJson(file.pubMmdEncodedJson!);
  91. }
  92. updatedFiles.add(file);
  93. }
  94. _logger.info('[Collection-$collectionID] parsed ${diff.length} '
  95. 'diff items ( ${updatedFiles.length} updated) in ${DateTime.now()
  96. .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<File> updatedFiles;
  106. final List<File> 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. }