mirror of
https://github.com/immich-app/immich.git
synced 2025-12-21 01:11:16 +03:00
feat(mobile): use efficient sync (#8842)
* feat(mobile): use efficient sync review feedback * adapt to changed server endpoints * formatting * fix memory lane bug * fix: bad merge * fix call not returning correct number of asset --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
committed by
GitHub
parent
acc611a3d9
commit
116043b2b4
@@ -40,18 +40,20 @@ class SyncService {
|
||||
|
||||
/// Syncs remote assets owned by the logged-in user to the DB
|
||||
/// Returns `true` if there were any changes
|
||||
Future<bool> syncRemoteAssetsToDb(
|
||||
User user,
|
||||
Future<(List<Asset>? toUpsert, List<String>? toDelete)> Function(
|
||||
User user,
|
||||
Future<bool> syncRemoteAssetsToDb({
|
||||
required List<User> users,
|
||||
required Future<(List<Asset>? toUpsert, List<String>? toDelete)> Function(
|
||||
List<User> users,
|
||||
DateTime since,
|
||||
) getChangedAssets,
|
||||
FutureOr<List<Asset>?> Function(User user) loadAssets,
|
||||
) =>
|
||||
required FutureOr<List<Asset>?> Function(User user, DateTime until)
|
||||
loadAssets,
|
||||
required FutureOr<List<User>?> Function() refreshUsers,
|
||||
}) =>
|
||||
_lock.run(
|
||||
() async =>
|
||||
await _syncRemoteAssetChanges(user, getChangedAssets) ??
|
||||
await _syncRemoteAssetsFull(user, loadAssets),
|
||||
await _syncRemoteAssetChanges(users, getChangedAssets) ??
|
||||
await _syncRemoteAssetsFull(refreshUsers, loadAssets),
|
||||
);
|
||||
|
||||
/// Syncs remote albums to the database
|
||||
@@ -111,7 +113,8 @@ class SyncService {
|
||||
both: (User a, User b) {
|
||||
if (!a.updatedAt.isAtSameMomentAs(b.updatedAt) ||
|
||||
a.isPartnerSharedBy != b.isPartnerSharedBy ||
|
||||
a.isPartnerSharedWith != b.isPartnerSharedWith) {
|
||||
a.isPartnerSharedWith != b.isPartnerSharedWith ||
|
||||
a.inTimeline != b.inTimeline) {
|
||||
toUpsert.add(a);
|
||||
return true;
|
||||
}
|
||||
@@ -149,17 +152,22 @@ class SyncService {
|
||||
|
||||
/// Efficiently syncs assets via changes. Returns `null` when a full sync is required.
|
||||
Future<bool?> _syncRemoteAssetChanges(
|
||||
User user,
|
||||
List<User> users,
|
||||
Future<(List<Asset>? toUpsert, List<String>? toDelete)> Function(
|
||||
User user,
|
||||
List<User> users,
|
||||
DateTime since,
|
||||
) getChangedAssets,
|
||||
) async {
|
||||
final DateTime? since = _db.eTags.getByIdSync(user.id)?.time?.toUtc();
|
||||
final currentUser = Store.get(StoreKey.currentUser);
|
||||
final DateTime? since =
|
||||
_db.eTags.getSync(currentUser.isarId)?.time?.toUtc();
|
||||
if (since == null) return null;
|
||||
final DateTime now = DateTime.now();
|
||||
final (toUpsert, toDelete) = await getChangedAssets(user, since);
|
||||
if (toUpsert == null || toDelete == null) return null;
|
||||
final (toUpsert, toDelete) = await getChangedAssets(users, since);
|
||||
if (toUpsert == null || toDelete == null) {
|
||||
await _clearUserAssetsETag(users);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (toDelete.isNotEmpty) {
|
||||
await handleRemoteAssetRemoval(toDelete);
|
||||
@@ -169,7 +177,7 @@ class SyncService {
|
||||
await upsertAssetsWithExif(updated);
|
||||
}
|
||||
if (toUpsert.isNotEmpty || toDelete.isNotEmpty) {
|
||||
await _updateUserAssetsETag(user, now);
|
||||
await _updateUserAssetsETag(users, now);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -203,11 +211,34 @@ class SyncService {
|
||||
|
||||
/// Syncs assets by loading and comparing all assets from the server.
|
||||
Future<bool> _syncRemoteAssetsFull(
|
||||
FutureOr<List<User>?> Function() refreshUsers,
|
||||
FutureOr<List<Asset>?> Function(User user, DateTime until) loadAssets,
|
||||
) async {
|
||||
final serverUsers = await refreshUsers();
|
||||
if (serverUsers == null) {
|
||||
_log.warning("_syncRemoteAssetsFull aborted because user refresh failed");
|
||||
return false;
|
||||
}
|
||||
await _syncUsersFromServer(serverUsers);
|
||||
final List<User> users = await _db.users
|
||||
.filter()
|
||||
.isPartnerSharedWithEqualTo(true)
|
||||
.or()
|
||||
.isarIdEqualTo(Store.get(StoreKey.currentUser).isarId)
|
||||
.findAll();
|
||||
bool changes = false;
|
||||
for (User u in users) {
|
||||
changes |= await _syncRemoteAssetsForUser(u, loadAssets);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
Future<bool> _syncRemoteAssetsForUser(
|
||||
User user,
|
||||
FutureOr<List<Asset>?> Function(User user) loadAssets,
|
||||
FutureOr<List<Asset>?> Function(User user, DateTime until) loadAssets,
|
||||
) async {
|
||||
final DateTime now = DateTime.now().toUtc();
|
||||
final List<Asset>? remote = await loadAssets(user);
|
||||
final List<Asset>? remote = await loadAssets(user, now);
|
||||
if (remote == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -225,7 +256,7 @@ class SyncService {
|
||||
|
||||
final (toAdd, toUpdate, toRemove) = _diffAssets(remote, inDb, remote: true);
|
||||
if (toAdd.isEmpty && toUpdate.isEmpty && toRemove.isEmpty) {
|
||||
await _updateUserAssetsETag(user, now);
|
||||
await _updateUserAssetsETag([user], now);
|
||||
return false;
|
||||
}
|
||||
final idsToDelete = toRemove.map((e) => e.id).toList();
|
||||
@@ -235,12 +266,19 @@ class SyncService {
|
||||
} on IsarError catch (e) {
|
||||
_log.severe("Failed to sync remote assets to db", e);
|
||||
}
|
||||
await _updateUserAssetsETag(user, now);
|
||||
await _updateUserAssetsETag([user], now);
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _updateUserAssetsETag(User user, DateTime time) =>
|
||||
_db.writeTxn(() => _db.eTags.put(ETag(id: user.id, time: time)));
|
||||
Future<void> _updateUserAssetsETag(List<User> users, DateTime time) {
|
||||
final etags = users.map((u) => ETag(id: u.id, time: time)).toList();
|
||||
return _db.writeTxn(() => _db.eTags.putAll(etags));
|
||||
}
|
||||
|
||||
Future<void> _clearUserAssetsETag(List<User> users) {
|
||||
final ids = users.map((u) => u.id).toList();
|
||||
return _db.writeTxn(() => _db.eTags.deleteAllById(ids));
|
||||
}
|
||||
|
||||
/// Syncs remote albums to the database
|
||||
/// returns `true` if there were any changes
|
||||
|
||||
Reference in New Issue
Block a user