Use completion handler to retrieve updated metadata after status change, fixing race condition in FileProviderDatabaseManager

Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
This commit is contained in:
Claudio Cambra 2023-03-14 23:15:02 +01:00
parent 7967ced04e
commit 9083f982d9
No known key found for this signature in database
GPG key ID: C839200C384636B0
2 changed files with 45 additions and 45 deletions

View file

@ -194,29 +194,26 @@ class NextcloudFilesDatabaseManager : NSObject {
}
}
func setStatusForItemMetadata(_ metadata: NextcloudItemMetadataTable, status: NextcloudItemMetadataTable.Status) -> NextcloudItemMetadataTable? {
func setStatusForItemMetadata(_ metadata: NextcloudItemMetadataTable, status: NextcloudItemMetadataTable.Status, completionHandler: @escaping(_ updatedMetadata: NextcloudItemMetadataTable?) -> Void) {
let database = ncDatabase()
var result: NextcloudItemMetadataTable?
do {
try database.write {
guard let result = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@", metadata.ocId).first else {
Logger.ncFilesDatabase.debug("Did not update status for item metadata as it was not found. ocID: \(metadata.ocId, privacy: .public)")
return
}
result.status = status.rawValue
database.add(result, update: .all)
Logger.ncFilesDatabase.debug("Updated status for item metadata. ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
completionHandler(NextcloudItemMetadataTable(value: result))
}
} catch let error {
Logger.ncFilesDatabase.error("Could not update status for item metadata with ocID: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), fileName: \(metadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash)), received error: \(error, privacy: .public)")
completionHandler(nil)
}
if result != nil {
return NextcloudItemMetadataTable(value: result!)
}
return nil
}
func addItemMetadata(_ metadata: NextcloudItemMetadataTable) {

View file

@ -149,49 +149,52 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
do {
let fileNameLocalPath = try localPathForNCFile(ocId: metadata.ocId, fileNameView: metadata.fileNameView)
guard let updatedMetadata = dbManager.setStatusForItemMetadata(metadata, status: NextcloudItemMetadataTable.Status.downloading) else {
Logger.fileProviderExtension.error("Could not acquire updated metadata of item with identifier: \(itemIdentifier.rawValue, privacy: .public)")
completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
return Progress()
}
dbManager.setStatusForItemMetadata(metadata, status: NextcloudItemMetadataTable.Status.downloading) { updatedMetadata in
self.ncKit.download(serverUrlFileName: serverUrlFileName,
fileNameLocalPath: fileNameLocalPath.path,
requestHandler: { _ in
guard let updatedMetadata = updatedMetadata else {
Logger.fileProviderExtension.error("Could not acquire updated metadata of item with identifier: \(itemIdentifier.rawValue, privacy: .public), unable to update item status to downloading")
completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
return
}
}, taskHandler: { task in
self.outstandingSessionTasks[serverUrlFileName] = task
NSFileProviderManager(for: self.domain)?.register(task, forItemWithIdentifier: itemIdentifier, completionHandler: { _ in })
}, progressHandler: { downloadProgress in
downloadProgress.copyCurrentStateToProgress(progress)
}) { _, etag, date, _, _, _, error in
self.outstandingSessionTasks.removeValue(forKey: serverUrlFileName)
self.ncKit.download(serverUrlFileName: serverUrlFileName,
fileNameLocalPath: fileNameLocalPath.path,
requestHandler: { _ in
if error == .success {
Logger.fileTransfer.debug("Acquired contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public) and filename: \(updatedMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
updatedMetadata.status = NextcloudItemMetadataTable.Status.normal.rawValue
updatedMetadata.date = (date ?? NSDate()) as Date
updatedMetadata.etag = etag ?? ""
}, taskHandler: { task in
self.outstandingSessionTasks[serverUrlFileName] = task
NSFileProviderManager(for: self.domain)?.register(task, forItemWithIdentifier: itemIdentifier, completionHandler: { _ in })
}, progressHandler: { downloadProgress in
downloadProgress.copyCurrentStateToProgress(progress)
}) { _, etag, date, _, _, _, error in
self.outstandingSessionTasks.removeValue(forKey: serverUrlFileName)
dbManager.addLocalFileMetadataFromItemMetadata(updatedMetadata)
dbManager.addItemMetadata(updatedMetadata)
if error == .success {
Logger.fileTransfer.debug("Acquired contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public) and filename: \(updatedMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
updatedMetadata.status = NextcloudItemMetadataTable.Status.normal.rawValue
updatedMetadata.date = (date ?? NSDate()) as Date
updatedMetadata.etag = etag ?? ""
guard let parentItemIdentifier = dbManager.parentItemIdentifierFromMetadata(updatedMetadata) else {
completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
return
dbManager.addLocalFileMetadataFromItemMetadata(updatedMetadata)
dbManager.addItemMetadata(updatedMetadata)
guard let parentItemIdentifier = dbManager.parentItemIdentifierFromMetadata(updatedMetadata) else {
completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
return
}
let fpItem = FileProviderItem(metadata: updatedMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
completionHandler(fileNameLocalPath, fpItem, nil)
} else {
Logger.fileTransfer.error("Could not acquire contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public) and fileName: \(updatedMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
updatedMetadata.status = NextcloudItemMetadataTable.Status.downloadError.rawValue
updatedMetadata.sessionError = error.errorDescription
dbManager.addItemMetadata(updatedMetadata)
completionHandler(nil, nil, error.toFileProviderError())
}
let fpItem = FileProviderItem(metadata: updatedMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
completionHandler(fileNameLocalPath, fpItem, nil)
} else {
Logger.fileTransfer.error("Could not acquire contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public) and fileName: \(updatedMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
updatedMetadata.status = NextcloudItemMetadataTable.Status.downloadError.rawValue
updatedMetadata.sessionError = error.errorDescription
dbManager.addItemMetadata(updatedMetadata)
completionHandler(nil, nil, error.toFileProviderError())
}
}
} catch let error {