2022-03-29 16:00:59 +03:00
/*
* Copyright ( C ) 2022 by Claudio Cambra < claudio . cambra @ nextcloud . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*/
import FileProvider
2023-01-26 22:50:40 +03:00
import NextcloudKit
2023-03-14 23:03:49 +03:00
import OSLog
2022-03-29 16:00:59 +03:00
class FileProviderEnumerator : NSObject , NSFileProviderEnumerator {
private let enumeratedItemIdentifier : NSFileProviderItemIdentifier
2023-03-08 01:30:50 +03:00
private var enumeratedItemMetadata : NextcloudItemMetadataTable ?
private var enumeratingSystemIdentifier : Bool {
return FileProviderEnumerator . isSystemIdentifier ( enumeratedItemIdentifier )
}
2023-03-07 03:40:17 +03:00
private let anchor = NSFileProviderSyncAnchor ( Date ( ) . description . data ( using : . utf8 ) ! ) // TODO: a c t u a l l y u s e t h i s i n N C K i t a n d s e r v e r r e q u e s t s
2023-01-26 22:50:40 +03:00
private static let maxItemsPerFileProviderPage = 100
2023-02-02 22:13:35 +03:00
let ncAccount : NextcloudAccount
let ncKit : NextcloudKit
2023-01-27 04:26:27 +03:00
var serverUrl : String = " "
2023-03-08 01:30:50 +03:00
private static func isSystemIdentifier ( _ identifier : NSFileProviderItemIdentifier ) -> Bool {
return identifier = = . rootContainer ||
identifier = = . trashContainer ||
identifier = = . workingSet
}
2022-03-29 16:00:59 +03:00
2023-02-02 22:13:35 +03:00
init ( enumeratedItemIdentifier : NSFileProviderItemIdentifier , ncAccount : NextcloudAccount , ncKit : NextcloudKit ) {
2022-03-29 16:00:59 +03:00
self . enumeratedItemIdentifier = enumeratedItemIdentifier
2023-01-26 22:50:40 +03:00
self . ncAccount = ncAccount
2023-02-02 22:13:35 +03:00
self . ncKit = ncKit
2023-01-10 22:25:26 +03:00
2023-03-08 01:30:50 +03:00
if FileProviderEnumerator . isSystemIdentifier ( enumeratedItemIdentifier ) {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Providing enumerator for a system defined container: \( enumeratedItemIdentifier . rawValue , privacy : . public ) " )
2023-01-27 04:26:27 +03:00
self . serverUrl = ncAccount . davFilesUrl
2023-01-10 22:25:26 +03:00
} else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Providing enumerator for item with identifier: \( enumeratedItemIdentifier . rawValue , privacy : . public ) " )
2023-01-10 22:25:26 +03:00
let dbManager = NextcloudFilesDatabaseManager . shared
2023-03-09 04:09:39 +03:00
enumeratedItemMetadata = dbManager . itemMetadataFromFileProviderItemIdentifier ( enumeratedItemIdentifier )
if enumeratedItemMetadata != nil {
self . serverUrl = enumeratedItemMetadata ! . serverUrl + " / " + enumeratedItemMetadata ! . fileName
2023-02-01 20:24:23 +03:00
} else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . error ( " Could not find itemMetadata for file with identifier: \( enumeratedItemIdentifier . rawValue , privacy : . public ) " )
2023-01-10 22:25:26 +03:00
}
}
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " Set up enumerator for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2022-03-29 16:00:59 +03:00
super . init ( )
}
func invalidate ( ) {
// TODO: p e r f o r m i n v a l i d a t i o n o f s e r v e r c o n n e c t i o n i f n e c e s s a r y
}
2023-01-12 23:49:28 +03:00
// MARK: - P r o t o c o l m e t h o d s
2022-03-29 16:00:59 +03:00
func enumerateItems ( for observer : NSFileProviderEnumerationObserver , startingAt page : NSFileProviderPage ) {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Received enumerate items request for enumerator with user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-14 23:03:49 +03:00
/*
- inspect the page to determine whether this is an initial or a follow - up request ( TODO )
2022-03-29 16:00:59 +03:00
If this is an enumerator for a directory , the root container or all directories :
- perform a server request to fetch directory contents
2023-03-14 23:03:49 +03:00
If this is an enumerator for the working set :
2022-03-29 16:00:59 +03:00
- perform a server request to update your local database
2023-03-14 23:03:49 +03:00
- fetch the working set from your local database
2022-03-29 16:00:59 +03:00
- inform the observer about the items returned by the server ( possibly multiple times )
- inform the observer that you are finished with this page
*/
2023-01-26 22:50:40 +03:00
2023-03-10 03:16:23 +03:00
let dbManager = NextcloudFilesDatabaseManager . shared
2023-03-14 18:01:34 +03:00
// I f w e d o n ' t h a v e a n y i t e m s i n t h e d a t a b a s e , i g n o r e t h i s a n d g o f o r a n o r m a l s e r v e r U r l r e a d .
// B y d e f a u l t w e s e t t h e s e r v e r U r l t o b e t h e w e b d a v f i l e s r o o t w h e n w e a r e p r o v i d e d a s y s t e m c o n t a i n e r i d .
// H o w e v e r , i f w e d o h a v e i t e m s , w e w a n t t o d o a r e c u r s i v e s c a n o f a l l t h e f o l d e r s i n t h e s e r v e r t h a t
// * * w e h a v e a l r e a d y e x p l o r e d * * . T h i s i s t o n o t k i l l t h e s e r v e r .
2023-03-10 03:16:23 +03:00
if enumeratedItemIdentifier = = . workingSet && dbManager . anyItemMetadatasForAccount ( ncAccount . ncKitAccount ) {
2023-03-10 05:21:01 +03:00
if page = = NSFileProviderPage . initialPageSortedByDate as NSFileProviderPage ||
page = = NSFileProviderPage . initialPageSortedByName as NSFileProviderPage {
2023-03-08 00:40:52 +03:00
2023-03-10 04:09:24 +03:00
2023-03-10 05:21:01 +03:00
let directoryMetadatas = dbManager . directoryMetadatas ( account : ncAccount . ncKitAccount )
var allMetadatas : [ NextcloudItemMetadataTable ] = [ ]
2023-03-10 04:09:24 +03:00
2023-03-14 18:06:20 +03:00
var serverError : NKError ?
2023-03-15 16:03:19 +03:00
// C r e a t e a s e r i a l d i s p a t c h q u e u e
let dispatchQueue = DispatchQueue ( label : " workingSetItemEnumerationQueue " , qos : . userInitiated )
let dispatchGroup = DispatchGroup ( ) // T o n o t i f y w h e n a l l n e t w o r k t a s k s a r e d o n e
dispatchGroup . notify ( queue : DispatchQueue . main ) {
guard serverError = = nil else {
observer . finishEnumeratingWithError ( serverError ! . error )
return
}
FileProviderEnumerator . completeEnumerationObserver ( observer , ncKit : self . ncKit , numPage : 1 , itemMetadatas : allMetadatas )
}
2023-03-10 04:09:24 +03:00
2023-03-10 05:21:01 +03:00
for directoryMetadata in directoryMetadatas {
2023-03-15 16:03:19 +03:00
dispatchGroup . enter ( ) // A d d t o o u t e r c o u n t e r
2023-03-14 18:06:20 +03:00
2023-03-15 16:03:19 +03:00
dispatchQueue . async {
2023-03-18 03:43:05 +03:00
let directoryServerUrl = directoryMetadata . serverUrl + " / " + directoryMetadata . fileName
2023-03-15 16:03:19 +03:00
guard serverError = = nil else {
2023-03-18 03:43:05 +03:00
Logger . enumeration . info ( " Skipping enumeration of directory for working set: \( directoryServerUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) as we have an error. " )
2023-03-10 05:21:01 +03:00
dispatchGroup . leave ( )
2023-03-15 16:03:19 +03:00
return ;
2023-03-10 04:09:24 +03:00
}
2023-03-15 16:03:19 +03:00
let currentNetworkTaskDispatchGroup = DispatchGroup ( ) // T o m a k e t h i s s e r i a l q u e u e w a i t u n t i l t h i s t a s k i s d o n e
currentNetworkTaskDispatchGroup . enter ( )
2023-03-10 04:09:24 +03:00
2023-03-18 03:43:05 +03:00
FileProviderEnumerator . readServerUrl ( directoryServerUrl , ncAccount : self . ncAccount , ncKit : self . ncKit ) { metadatas , _ , _ , _ , readError in
2023-03-15 16:03:19 +03:00
guard readError = = nil else {
2023-03-18 03:43:05 +03:00
Logger . enumeration . error ( " Finishing enumeration of working set directory \( directoryServerUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with error \( readError ! . localizedDescription , privacy : . public ) " )
2023-03-10 04:09:24 +03:00
2023-03-15 16:03:19 +03:00
let nkError = NKError ( error : readError ! )
if nkError . isUnauthenticatedError || nkError . isCouldntConnectError {
// I f i t i s a c r i t i c a l e r r o r t h e n s t o p , i f n o t t h e n c o n t i n u e
Logger . enumeration . error ( " Error will affect next enumerated items, so stopping enumeration. " )
serverError = nkError
}
2023-03-14 23:03:49 +03:00
2023-03-15 16:03:19 +03:00
currentNetworkTaskDispatchGroup . leave ( )
return
}
if let metadatas = metadatas {
allMetadatas += metadatas
} else {
2023-03-18 03:43:05 +03:00
allMetadatas += dbManager . itemMetadatas ( account : self . ncAccount . ncKitAccount , serverUrl : directoryServerUrl )
2023-03-15 16:03:19 +03:00
}
currentNetworkTaskDispatchGroup . leave ( )
}
currentNetworkTaskDispatchGroup . wait ( )
dispatchGroup . leave ( ) // N o w l o w e r o u t e r c o u n t e r
2023-03-14 18:06:20 +03:00
}
2023-03-10 04:09:24 +03:00
}
2023-03-10 05:21:01 +03:00
2023-03-15 16:03:19 +03:00
return
2023-03-10 05:21:01 +03:00
} else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Enumerating page \( page . rawValue ) of working set for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-14 23:03:49 +03:00
// T O D O !
2023-03-10 05:21:01 +03:00
observer . finishEnumerating ( upTo : nil )
2023-03-10 04:09:24 +03:00
}
2023-03-08 00:40:52 +03:00
return
} else if enumeratedItemIdentifier = = . trashContainer {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Enumerating trash set for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-08 00:40:52 +03:00
// T O D O !
2023-01-26 22:50:40 +03:00
observer . finishEnumerating ( upTo : nil )
return
}
2023-03-09 03:19:00 +03:00
guard serverUrl != " " else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . error ( " Enumerator has empty serverUrl -- can't enumerate that! For identifier: \( self . enumeratedItemIdentifier . rawValue , privacy : . public ) " )
2023-03-09 03:19:00 +03:00
observer . finishEnumeratingWithError ( NSFileProviderError ( . noSuchItem ) )
return
}
2023-03-10 03:16:23 +03:00
// TODO: M a k e b e t t e r u s e o f p a g i n a t i o n a n d a n d l e p a g i n g p r o p e r l y
2023-01-26 22:50:40 +03:00
if page = = NSFileProviderPage . initialPageSortedByDate as NSFileProviderPage ||
page = = NSFileProviderPage . initialPageSortedByName as NSFileProviderPage {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Enumerating initial page for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 03:19:00 +03:00
FileProviderEnumerator . readServerUrl ( serverUrl , ncAccount : ncAccount , ncKit : ncKit ) { _ , _ , _ , _ , readError in
guard readError = = nil else {
2023-03-15 19:21:31 +03:00
Logger . enumeration . error ( " Finishing enumeration for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with error \( readError ! . localizedDescription , privacy : . public ) " )
2023-03-13 16:27:17 +03:00
2023-03-13 17:09:43 +03:00
let nkReadError = NKError ( error : readError ! )
observer . finishEnumeratingWithError ( nkReadError . toFileProviderError ( ) )
2023-03-09 04:09:39 +03:00
return
2023-03-09 03:19:00 +03:00
}
let ncKitAccount = self . ncAccount . ncKitAccount
// R e t u r n a l l n o w k n o w n m e t a d a t a s
2023-03-09 04:09:39 +03:00
var metadatas : [ NextcloudItemMetadataTable ]
if self . enumeratingSystemIdentifier || ( self . enumeratedItemMetadata != nil && self . enumeratedItemMetadata ! . directory ) {
metadatas = NextcloudFilesDatabaseManager . shared . itemMetadatas ( account : ncKitAccount , serverUrl : self . serverUrl )
} else if ( self . enumeratedItemMetadata != nil ) {
guard let updatedEnumeratedItemMetadata = NextcloudFilesDatabaseManager . shared . itemMetadataFromOcId ( self . enumeratedItemMetadata ! . ocId ) else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . error ( " Could not finish enumeration for user: \( ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) as the enumerated item could not be fetched from database. \( self . enumeratedItemIdentifier . rawValue , privacy : . public ) " )
2023-03-09 04:09:39 +03:00
observer . finishEnumeratingWithError ( NSFileProviderError ( . noSuchItem ) )
return
}
2023-03-09 14:54:18 +03:00
2023-03-09 04:09:39 +03:00
metadatas = [ updatedEnumeratedItemMetadata ]
2023-03-14 23:03:49 +03:00
} else { // W e n e e d t o h a v e a n e n u m e r a t e d I t e m M e t a d a t a t o h a v e a n o n e m p t y s e r v e r U r l
2023-03-14 23:26:52 +03:00
Logger . enumeration . error ( " Cannot finish enumeration for user: \( ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) as we do not have a valid server URL. NOTE: this error should not be possible and indicates something is going wrong before. " )
2023-03-09 04:09:39 +03:00
observer . finishEnumeratingWithError ( NSFileProviderError ( . noSuchItem ) )
return
}
2023-03-09 03:19:00 +03:00
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " Finished reading serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) for user: \( ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) . Processed \( metadatas . count ) metadatas " )
2023-03-09 03:19:00 +03:00
2023-03-09 14:54:18 +03:00
FileProviderEnumerator . completeEnumerationObserver ( observer , ncKit : self . ncKit , numPage : 1 , itemMetadatas : metadatas )
2023-01-26 22:50:40 +03:00
}
2023-01-27 04:44:34 +03:00
return ;
2023-01-26 22:50:40 +03:00
}
2023-01-27 04:44:34 +03:00
let numPage = Int ( String ( data : page . rawValue , encoding : . utf8 ) ! ) !
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Enumerating page \( numPage , privacy : . public ) for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 03:19:00 +03:00
// TODO: H a n d l e p a g i n g p r o p e r l y
// F i l e P r o v i d e r E n u m e r a t o r . c o m p l e t e O b s e r v e r ( o b s e r v e r , n c K i t : n c K i t , n u m P a g e : n u m P a g e , i t e m M e t a d a t a s : n i l )
observer . finishEnumerating ( upTo : nil )
2022-03-29 16:00:59 +03:00
}
func enumerateChanges ( for observer : NSFileProviderChangeObserver , from anchor : NSFileProviderSyncAnchor ) {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Received enumerate changes request for enumerator for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 15:14:03 +03:00
/*
2023-03-14 23:03:49 +03:00
- query the server for updates since the passed - in sync anchor ( TODO )
2022-03-29 16:00:59 +03:00
2023-03-14 23:03:49 +03:00
If this is an enumerator for the working set :
2022-03-29 16:00:59 +03:00
- note the changes in your local database
- inform the observer about item deletions and updates ( modifications + insertions )
- inform the observer when you have finished enumerating up to a subsequent sync anchor
*/
2023-03-09 15:14:03 +03:00
if enumeratedItemIdentifier = = . workingSet {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Enumerating changes in working set for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 15:14:03 +03:00
2023-03-18 15:57:02 +03:00
FileProviderEnumerator . fullRecursiveScan ( ncAccount : self . ncAccount , ncKit : self . ncKit , scanChangesOnly : true ) { _ , newMetadatas , updatedMetadatas , deletedMetadatas , error in
guard error = = nil else {
Logger . enumeration . info ( " Finished recursive change enumeration of working set for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with error: \( error ! . errorDescription , privacy : . public ) " )
observer . finishEnumeratingWithError ( error ! . toFileProviderError ( ) )
return ;
}
2023-03-15 16:37:53 +03:00
Logger . enumeration . info ( " Finished recursive change enumeration of working set for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) . Enumerating items. " )
2023-03-17 22:37:22 +03:00
2023-03-15 16:37:53 +03:00
FileProviderEnumerator . completeChangesObserver ( observer ,
anchor : anchor ,
ncKit : self . ncKit ,
newMetadatas : newMetadatas ,
updatedMetadatas : updatedMetadatas ,
2023-03-18 16:10:24 +03:00
deletedMetadatas : deletedMetadatas )
2023-03-15 16:37:53 +03:00
}
2023-03-09 15:14:03 +03:00
return
} else if enumeratedItemIdentifier = = . trashContainer {
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Enumerating changes in trash set for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 15:14:03 +03:00
// T O D O !
observer . finishEnumeratingChanges ( upTo : anchor , moreComing : false )
return
}
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " Enumerating changes for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 15:14:03 +03:00
2023-03-09 15:27:57 +03:00
// N o m a t t e r w h a t h a p p e n s h e r e w e f i n i s h e n u m e r a t i o n i n s o m e w a y , e i t h e r f r o m t h e e r r o r
// h a n d l i n g b e l o w o r f r o m t h e c o m p l e t e C h a n g e s O b s e r v e r
2023-03-13 16:59:46 +03:00
FileProviderEnumerator . readServerUrl ( serverUrl , ncAccount : ncAccount , ncKit : ncKit , stopAtMatchingEtags : true ) { _ , newMetadatas , updatedMetadatas , deletedMetadatas , readError in
2023-03-18 15:24:37 +03:00
// I f w e g e t a 4 0 4 w e m i g h t a d d m o r e d e l e t e d m e t a d a t a s
var currentDeletedMetadatas : [ NextcloudItemMetadataTable ] = [ ]
if let notNilDeletedMetadatas = deletedMetadatas {
currentDeletedMetadatas = notNilDeletedMetadatas
}
2023-03-09 15:14:03 +03:00
guard readError = = nil else {
2023-03-15 19:21:31 +03:00
Logger . enumeration . error ( " Finishing enumeration of changes for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) with error: \( readError ! . localizedDescription , privacy : . public ) " )
2023-03-09 18:51:31 +03:00
2023-03-13 17:09:43 +03:00
let nkReadError = NKError ( error : readError ! )
let fpError = nkReadError . toFileProviderError ( )
2023-03-13 16:15:32 +03:00
2023-03-13 17:09:43 +03:00
if nkReadError . isNotFoundError {
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " 404 error means item no longer exists. Deleting metadata and reporting \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) as deletion without error " )
2023-03-09 18:51:31 +03:00
2023-03-13 17:09:43 +03:00
guard let itemMetadata = self . enumeratedItemMetadata else {
2023-03-14 23:03:49 +03:00
Logger . enumeration . error ( " Invalid enumeratedItemMetadata, could not delete metadata nor report deletion " )
2023-03-13 17:09:43 +03:00
observer . finishEnumeratingWithError ( fpError )
2023-03-13 16:15:32 +03:00
return
2023-03-09 18:51:31 +03:00
}
2023-03-13 16:27:17 +03:00
2023-03-13 17:09:43 +03:00
let dbManager = NextcloudFilesDatabaseManager . shared
if itemMetadata . directory {
2023-03-18 15:24:37 +03:00
if let deletedDirectoryMetadatas = dbManager . deleteDirectoryAndSubdirectoriesMetadata ( ocId : itemMetadata . ocId ) {
currentDeletedMetadatas += deletedDirectoryMetadatas
} else {
Logger . enumeration . error ( " Something went wrong when recursively deleting directory not found. " )
}
2023-03-13 17:09:43 +03:00
} else {
dbManager . deleteItemMetadata ( ocId : itemMetadata . ocId )
}
FileProviderEnumerator . completeChangesObserver ( observer , anchor : anchor , ncKit : self . ncKit , newMetadatas : nil , updatedMetadatas : nil , deletedMetadatas : [ itemMetadata ] )
2023-03-13 16:27:17 +03:00
return
2023-03-13 17:09:43 +03:00
} else if nkReadError . isNoChangesError { // A l l i s w e l l , j u s t n o c h a n g e d e t a g s
2023-03-14 23:03:49 +03:00
Logger . enumeration . info ( " Error was to say no changed files -- not bad error. Finishing change enumeration. " )
2023-03-13 17:09:43 +03:00
observer . finishEnumeratingChanges ( upTo : anchor , moreComing : false )
return ;
2023-03-09 18:51:31 +03:00
}
2023-03-13 17:09:43 +03:00
observer . finishEnumeratingWithError ( fpError )
2023-03-09 15:14:03 +03:00
return
}
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " Finished reading serverUrl: \( self . serverUrl , privacy : OSLogPrivacy . auto ( mask : . hash ) ) for user: \( self . ncAccount . ncKitAccount , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-03-09 15:14:03 +03:00
2023-03-10 03:16:23 +03:00
FileProviderEnumerator . completeChangesObserver ( observer , anchor : anchor , ncKit : self . ncKit , newMetadatas : newMetadatas , updatedMetadatas : updatedMetadatas , deletedMetadatas : deletedMetadatas )
2023-03-09 15:14:03 +03:00
}
2022-03-29 16:00:59 +03:00
}
func currentSyncAnchor ( completionHandler : @ escaping ( NSFileProviderSyncAnchor ? ) -> Void ) {
completionHandler ( anchor )
}
2023-01-12 23:50:35 +03:00
// MARK: - H e l p e r m e t h o d s
2023-03-15 14:47:08 +03:00
private static func completeEnumerationObserver ( _ observer : NSFileProviderEnumerationObserver , ncKit : NextcloudKit , numPage : Int , itemMetadatas : [ NextcloudItemMetadataTable ] ) {
2023-01-26 22:50:40 +03:00
2023-01-12 23:50:35 +03:00
var items : [ NSFileProviderItem ] = [ ]
2023-03-09 03:19:00 +03:00
for itemMetadata in itemMetadatas {
2023-01-27 04:44:34 +03:00
if itemMetadata . e2eEncrypted {
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " Skipping encrypted metadata in enumeration: \( itemMetadata . ocId ) \( itemMetadata . fileName , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-01-27 04:44:34 +03:00
continue
}
2023-01-12 23:50:35 +03:00
2023-03-13 14:34:05 +03:00
if let parentItemIdentifier = NextcloudFilesDatabaseManager . shared . parentItemIdentifierFromMetadata ( itemMetadata ) {
2023-02-02 22:13:35 +03:00
let item = FileProviderItem ( metadata : itemMetadata , parentItemIdentifier : parentItemIdentifier , ncKit : ncKit )
2023-03-14 23:26:52 +03:00
Logger . enumeration . debug ( " Will enumerate item with ocId: \( itemMetadata . ocId ) and name: \( itemMetadata . fileName , privacy : OSLogPrivacy . auto ( mask : . hash ) ) " )
2023-01-12 23:50:35 +03:00
items . append ( item )
2023-01-27 04:44:34 +03:00
} else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . error ( " Could not get valid parentItemIdentifier for item with ocId: \( itemMetadata . ocId , privacy : . public ) and name: \( itemMetadata . fileName , privacy : OSLogPrivacy . auto ( mask : . hash ) ) , skipping enumeration " )
2023-01-12 23:50:35 +03:00
}
}
observer . didEnumerate ( items )
2023-03-14 23:03:49 +03:00
Logger . enumeration . info ( " Did enumerate \( items . count ) items " )
2023-01-12 23:50:35 +03:00
2023-03-09 03:19:00 +03:00
// TODO: H a n d l e p a g i n g p r o p e r l y
/*
2023-01-12 23:50:35 +03:00
if items . count = = maxItemsPerFileProviderPage {
let nextPage = numPage + 1
let providerPage = NSFileProviderPage ( " \( nextPage ) " . data ( using : . utf8 ) ! )
observer . finishEnumerating ( upTo : providerPage )
} else {
observer . finishEnumerating ( upTo : nil )
}
2023-03-09 03:19:00 +03:00
*/
observer . finishEnumerating ( upTo : NSFileProviderPage ( " \( numPage ) " . data ( using : . utf8 ) ! ) )
2023-01-12 23:50:35 +03:00
}
2023-01-26 22:50:40 +03:00
2023-03-09 17:45:38 +03:00
private static func completeChangesObserver ( _ observer : NSFileProviderChangeObserver , anchor : NSFileProviderSyncAnchor , ncKit : NextcloudKit , newMetadatas : [ NextcloudItemMetadataTable ] ? , updatedMetadatas : [ NextcloudItemMetadataTable ] ? , deletedMetadatas : [ NextcloudItemMetadataTable ] ? ) {
guard newMetadatas != nil || updatedMetadatas != nil || deletedMetadatas != nil else {
2023-03-14 23:03:49 +03:00
Logger . enumeration . error ( " Received invalid newMetadatas, updatedMetadatas or deletedMetadatas. Finished enumeration of changes with error. " )
2023-03-09 15:27:57 +03:00
observer . finishEnumeratingWithError ( NSFileProviderError ( . noSuchItem ) )
return
}
2023-03-09 17:45:38 +03:00
// O b s e r v e r d o e s n o t c a r e a b o u t n e w v s u p d a t e d , s o j o i n
var allUpdatedMetadatas : [ NextcloudItemMetadataTable ] = [ ]
var allDeletedMetadatas : [ NextcloudItemMetadataTable ] = [ ]
if let newMetadatas = newMetadatas {
allUpdatedMetadatas += newMetadatas
}
if let updatedMetadatas = updatedMetadatas {
allUpdatedMetadatas += updatedMetadatas
}
if let deletedMetadatas = deletedMetadatas {
allDeletedMetadatas = deletedMetadatas
}
2023-03-09 15:27:57 +03:00
var allFpItemUpdates : [ FileProviderItem ] = [ ]
2023-03-09 17:45:38 +03:00
var allFpItemDeletionsIdentifiers = Array ( allDeletedMetadatas . map { NSFileProviderItemIdentifier ( $0 . ocId ) } )
2023-03-09 15:27:57 +03:00
2023-03-11 00:25:28 +03:00
for updMetadata in allUpdatedMetadatas {
2023-03-13 14:34:05 +03:00
guard let parentItemIdentifier = NextcloudFilesDatabaseManager . shared . parentItemIdentifierFromMetadata ( updMetadata ) else {
2023-03-14 23:26:52 +03:00
Logger . enumeration . warning ( " Not enumerating change for metadata: \( updMetadata . ocId ) \( updMetadata . fileName , privacy : OSLogPrivacy . auto ( mask : . hash ) ) as could not get parent item metadata. " )
2023-03-11 00:25:28 +03:00
continue
}
2023-03-09 15:27:57 +03:00
2023-03-11 00:25:28 +03:00
guard ! updMetadata . e2eEncrypted else {
// P r e c a u t i o n , i f a l l g o e s w e l l i n N K F i l e c o n v e r s i o n t h e n t h i s s h o u l d n o t h a p p e n
// TODO: R e m o v e w h e n E 2 E E s u p p o r t e d
2023-03-14 23:26:52 +03:00
Logger . enumeration . info ( " Encrypted metadata in changes enumeration \( updMetadata . ocId ) \( updMetadata . fileName , privacy : OSLogPrivacy . auto ( mask : . hash ) ) , adding to deletions " )
2023-03-11 00:25:28 +03:00
allFpItemDeletionsIdentifiers . append ( NSFileProviderItemIdentifier ( updMetadata . ocId ) )
continue
2023-03-10 20:36:25 +03:00
}
2023-03-11 00:25:28 +03:00
let fpItem = FileProviderItem ( metadata : updMetadata , parentItemIdentifier : parentItemIdentifier , ncKit : ncKit )
allFpItemUpdates . append ( fpItem )
2023-03-09 15:27:57 +03:00
}
2023-03-09 17:45:38 +03:00
if ! allFpItemUpdates . isEmpty {
observer . didUpdate ( allFpItemUpdates )
}
if ! allFpItemDeletionsIdentifiers . isEmpty {
observer . didDeleteItems ( withIdentifiers : allFpItemDeletionsIdentifiers )
}
2023-03-14 23:03:49 +03:00
Logger . enumeration . info ( " Processed \( allUpdatedMetadatas . count ) new or updated metadatas, \( allDeletedMetadatas . count ) deleted metadatas. " )
2023-03-09 17:45:38 +03:00
observer . finishEnumeratingChanges ( upTo : anchor , moreComing : false )
2023-03-09 15:27:57 +03:00
}
2022-03-29 16:00:59 +03:00
}