mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix: ignore duplicate cloud ID updates (#25271)
* fix: ignore duplicate remote updates * update cloudId when any one of the ETag part is mismatched --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
80a5444bf4
commit
2f3fbd7dc5
1 changed files with 20 additions and 11 deletions
|
|
@ -21,6 +21,7 @@ Future<void> syncCloudIds(ProviderContainer ref) async {
|
||||||
if (!CurrentPlatform.isIOS) {
|
if (!CurrentPlatform.isIOS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final logger = Logger('migrateCloudIds');
|
||||||
|
|
||||||
final db = ref.read(driftProvider);
|
final db = ref.read(driftProvider);
|
||||||
// Populate cloud IDs for local assets that don't have one yet
|
// Populate cloud IDs for local assets that don't have one yet
|
||||||
|
|
@ -29,9 +30,7 @@ Future<void> syncCloudIds(ProviderContainer ref) async {
|
||||||
final serverInfo = await ref.read(serverInfoProvider.notifier).getServerInfo();
|
final serverInfo = await ref.read(serverInfoProvider.notifier).getServerInfo();
|
||||||
final canUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 4);
|
final canUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 4);
|
||||||
if (!canUpdateMetadata) {
|
if (!canUpdateMetadata) {
|
||||||
Logger(
|
logger.fine('Server version does not support asset metadata updates. Skipping cloudId migration.');
|
||||||
'migrateCloudIds',
|
|
||||||
).fine('Server version does not support asset metadata updates. Skipping cloudId migration.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final canBulkUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 5);
|
final canBulkUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 5);
|
||||||
|
|
@ -40,25 +39,35 @@ Future<void> syncCloudIds(ProviderContainer ref) async {
|
||||||
try {
|
try {
|
||||||
await ref.read(syncStreamServiceProvider).sync();
|
await ref.read(syncStreamServiceProvider).sync();
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logger('migrateCloudIds').fine('Failed to complete remote sync before cloudId migration.', e, s);
|
logger.fine('Failed to complete remote sync before cloudId migration.', e, s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the mapping for backed up assets that have a cloud ID locally but do not have a cloud ID on the server
|
// Fetch the mapping for backed up assets that have a cloud ID locally but do not have a cloud ID on the server
|
||||||
final currentUser = ref.read(currentUserProvider);
|
final currentUser = ref.read(currentUserProvider);
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
Logger('migrateCloudIds').warning('Current user is null. Aborting cloudId migration.');
|
logger.warning('Current user is null. Aborting cloudId migration.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final mappingsToUpdate = await _fetchCloudIdMappings(db, currentUser.id);
|
final mappingsToUpdate = await _fetchCloudIdMappings(db, currentUser.id);
|
||||||
|
// Deduplicate mappings as a single remote asset ID can match multiple local assets
|
||||||
|
final seenRemoteAssetIds = <String>{};
|
||||||
|
final uniqueMapping = mappingsToUpdate.where((mapping) {
|
||||||
|
if (!seenRemoteAssetIds.add(mapping.remoteAssetId)) {
|
||||||
|
logger.fine('Duplicate remote asset ID found: ${mapping.remoteAssetId}. Skipping duplicate entry.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
final assetApi = ref.read(apiServiceProvider).assetsApi;
|
final assetApi = ref.read(apiServiceProvider).assetsApi;
|
||||||
|
|
||||||
if (canBulkUpdateMetadata) {
|
if (canBulkUpdateMetadata) {
|
||||||
await _bulkUpdateCloudIds(assetApi, mappingsToUpdate);
|
await _bulkUpdateCloudIds(assetApi, uniqueMapping);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await _sequentialUpdateCloudIds(assetApi, mappingsToUpdate);
|
await _sequentialUpdateCloudIds(assetApi, uniqueMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _sequentialUpdateCloudIds(AssetsApi assetsApi, List<_CloudIdMapping> mappings) async {
|
Future<void> _sequentialUpdateCloudIds(AssetsApi assetsApi, List<_CloudIdMapping> mappings) async {
|
||||||
|
|
@ -152,10 +161,10 @@ Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift, String userId)
|
||||||
// Skip locked assets as we cannot update them without unlocking first
|
// Skip locked assets as we cannot update them without unlocking first
|
||||||
drift.remoteAssetEntity.visibility.isNotValue(AssetVisibility.locked.index) &
|
drift.remoteAssetEntity.visibility.isNotValue(AssetVisibility.locked.index) &
|
||||||
(drift.remoteAssetCloudIdEntity.cloudId.isNull() |
|
(drift.remoteAssetCloudIdEntity.cloudId.isNull() |
|
||||||
((drift.remoteAssetCloudIdEntity.adjustmentTime.isNotExp(drift.localAssetEntity.adjustmentTime)) &
|
drift.remoteAssetCloudIdEntity.adjustmentTime.isNotExp(drift.localAssetEntity.adjustmentTime) |
|
||||||
(drift.remoteAssetCloudIdEntity.latitude.isNotExp(drift.localAssetEntity.latitude)) &
|
drift.remoteAssetCloudIdEntity.latitude.isNotExp(drift.localAssetEntity.latitude) |
|
||||||
(drift.remoteAssetCloudIdEntity.longitude.isNotExp(drift.localAssetEntity.longitude)) &
|
drift.remoteAssetCloudIdEntity.longitude.isNotExp(drift.localAssetEntity.longitude) |
|
||||||
(drift.remoteAssetCloudIdEntity.createdAt.isNotExp(drift.localAssetEntity.createdAt)))),
|
drift.remoteAssetCloudIdEntity.createdAt.isNotExp(drift.localAssetEntity.createdAt)),
|
||||||
);
|
);
|
||||||
return query.map((row) {
|
return query.map((row) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue