@ -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 > user s ,
required Future < ( List < Asset > ? toUpsert , List < String > ? toDelete ) > Function (
List< User> user s ,
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 ( user s , 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> user s ,
Future < ( List < Asset > ? toUpsert , List < String > ? toDelete ) > Function (
User user ,
List< User> user s ,
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 ( user s , 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