folder_service.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import 'dart:developer';
  2. import 'package:dio/dio.dart';
  3. import 'package:logging/logging.dart';
  4. import 'package:photos/core/configuration.dart';
  5. import 'package:photos/db/folders_db.dart';
  6. import 'package:photos/db/files_db.dart';
  7. import 'package:photos/events/remote_sync_event.dart';
  8. import 'package:photos/events/user_authenticated_event.dart';
  9. import 'package:photos/models/folder.dart';
  10. import 'package:photos/models/file.dart';
  11. import 'core/event_bus.dart';
  12. class FolderSharingService {
  13. final _logger = Logger("FolderSharingService");
  14. final _dio = Dio();
  15. static final _diffLimit = 100;
  16. bool _isSyncInProgress = false;
  17. FolderSharingService._privateConstructor() {
  18. Bus.instance.on<UserAuthenticatedEvent>().listen((event) {
  19. sync();
  20. });
  21. }
  22. static final FolderSharingService instance =
  23. FolderSharingService._privateConstructor();
  24. Future<void> sync() {
  25. _logger.info("Syncing...");
  26. if (_isSyncInProgress || !Configuration.instance.hasConfiguredAccount()) {
  27. return Future.value();
  28. }
  29. _isSyncInProgress = true;
  30. return getFolders().then((f) async {
  31. var folders = f.toSet();
  32. var currentFolders = await FoldersDB.instance.getFolders();
  33. for (final currentFolder in currentFolders) {
  34. if (!folders.contains(currentFolder)) {
  35. _logger.info("Folder deleted: " + currentFolder.toString());
  36. await FilesDB.instance.deleteFilesInRemoteFolder(currentFolder.id);
  37. await FoldersDB.instance.deleteFolder(currentFolder);
  38. }
  39. }
  40. for (final folder in folders) {
  41. if (folder.ownerID != Configuration.instance.getUserID()) {
  42. await syncDiff(folder);
  43. await FoldersDB.instance.putFolder(folder);
  44. }
  45. }
  46. Bus.instance.fire(RemoteSyncEvent(true));
  47. _isSyncInProgress = false;
  48. return Future.value();
  49. });
  50. }
  51. Future<void> syncDiff(Folder folder) async {
  52. int lastSyncTimestamp = 0;
  53. try {
  54. File file =
  55. await FilesDB.instance.getLastSyncedFileInRemoteFolder(folder.id);
  56. lastSyncTimestamp = file.updationTime;
  57. } catch (e) {
  58. // Folder has never been synced
  59. }
  60. var diff = await getDiff(folder.id, lastSyncTimestamp, _diffLimit);
  61. for (File file in diff) {
  62. try {
  63. var existingPhoto =
  64. await FilesDB.instance.getMatchingRemoteFile(file.uploadedFileID);
  65. await FilesDB.instance.update(
  66. existingPhoto.generatedID, file.uploadedFileID, file.updationTime);
  67. } catch (e) {
  68. await FilesDB.instance.insert(file);
  69. }
  70. }
  71. if (diff.length == _diffLimit) {
  72. await syncDiff(folder);
  73. }
  74. }
  75. Future<List<File>> getDiff(
  76. int folderId, int sinceTimestamp, int limit) async {
  77. Response response = await _dio.get(
  78. Configuration.instance.getHttpEndpoint() +
  79. "/folders/diff/" +
  80. folderId.toString(),
  81. options:
  82. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  83. queryParameters: {
  84. "sinceTimestamp": sinceTimestamp,
  85. "limit": limit,
  86. },
  87. ).catchError((e) => _logger.severe(e));
  88. if (response != null) {
  89. return (response.data["diff"] as List).map((p) {
  90. File file = new File.fromJson(p);
  91. file.localID = null;
  92. file.remoteFolderID = folderId;
  93. return file;
  94. }).toList();
  95. } else {
  96. return List<File>();
  97. }
  98. }
  99. Future<List<Folder>> getFolders() async {
  100. return _dio
  101. .get(
  102. Configuration.instance.getHttpEndpoint() + "/folders/",
  103. options:
  104. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  105. )
  106. .then((foldersResponse) {
  107. return (foldersResponse.data as List)
  108. .map((f) => Folder.fromMap(f))
  109. .toList();
  110. });
  111. }
  112. Future<Folder> getFolder(String deviceFolder) async {
  113. return _dio
  114. .get(
  115. Configuration.instance.getHttpEndpoint() + "/folders/folder/",
  116. queryParameters: {
  117. "deviceFolder": deviceFolder,
  118. },
  119. options:
  120. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  121. )
  122. .then((response) {
  123. return Folder.fromMap(response.data);
  124. }).catchError((e) {
  125. try {
  126. return Folder(
  127. null,
  128. Configuration.instance.getEmail() + "s " + deviceFolder,
  129. Configuration.instance.getUserID(),
  130. deviceFolder,
  131. Set<int>(),
  132. null,
  133. );
  134. } catch (e) {
  135. _logger.severe(e);
  136. return null;
  137. }
  138. });
  139. }
  140. Future<Map<int, bool>> getSharingStatus(Folder folder) async {
  141. return _dio
  142. .get(
  143. Configuration.instance.getHttpEndpoint() + "/users",
  144. options:
  145. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  146. )
  147. .then((response) {
  148. final users = (response.data["users"] as List).toList();
  149. final result = Map<int, bool>();
  150. for (final user in users) {
  151. if (user["id"] != Configuration.instance.getUserID()) {
  152. result[user["id"]] = folder.sharedWith.contains(user["id"]);
  153. }
  154. }
  155. return result;
  156. });
  157. }
  158. Future<void> updateFolder(Folder folder) {
  159. return _dio
  160. .put(Configuration.instance.getHttpEndpoint() + "/folders/",
  161. options: Options(
  162. headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  163. data: folder.toMap())
  164. .then((response) => log(response.toString()))
  165. .catchError((error) => log(error.toString()));
  166. }
  167. }