Remove redundant directory metadata tables in File Provider

Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
This commit is contained in:
Claudio Cambra 2023-03-18 01:43:05 +01:00
Родитель 2e70c82663
Коммит 872186248a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: C839200C384636B0
6 изменённых файлов: 100 добавлений и 269 удалений

Просмотреть файл

@ -1,38 +0,0 @@
/*
* Copyright (C) 2023 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 Foundation
import RealmSwift
class NextcloudDirectoryMetadataTable: Object {
func isInSameRemoteState(_ comparingMetadata: NextcloudDirectoryMetadataTable) -> Bool {
return comparingMetadata.etag == self.etag &&
comparingMetadata.e2eEncrypted == self.e2eEncrypted &&
comparingMetadata.favorite == self.favorite &&
comparingMetadata.permissions == self.permissions
}
@Persisted(primaryKey: true) var ocId: String
@Persisted var account = ""
@Persisted var colorFolder: String?
@Persisted var e2eEncrypted: Bool = false
@Persisted var etag = ""
@Persisted var favorite: Bool = false
@Persisted var fileId = ""
@Persisted var offline: Bool = false
@Persisted var permissions = ""
@Persisted var richWorkspace: String?
@Persisted var serverUrl = ""
@Persisted var parentDirectoryServerUrl = ""
}

Просмотреть файл

@ -54,7 +54,7 @@ class NextcloudFilesDatabaseManager : NSObject {
let config = Realm.Configuration(
fileURL: self.databasePath,
schemaVersion: self.schemaVersion,
objectTypes: [NextcloudItemMetadataTable.self, NextcloudDirectoryMetadataTable.self, NextcloudLocalFileMetadataTable.self]
objectTypes: [NextcloudItemMetadataTable.self, NextcloudLocalFileMetadataTable.self]
)
Realm.Configuration.defaultConfiguration = config
@ -290,163 +290,60 @@ class NextcloudFilesDatabaseManager : NSObject {
return nil
}
func directoryMetadata(account: String, serverUrl: String) -> NextcloudDirectoryMetadataTable? {
if let metadata = ncDatabase().objects(NextcloudDirectoryMetadataTable.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first {
return NextcloudDirectoryMetadataTable(value: metadata)
func directoryMetadata(account: String, serverUrl: String) -> NextcloudItemMetadataTable? {
// We want to split by "/" (e.g. cloud.nc.com/files/a/b) but we need to be mindful of "https://c.nc.com"
let problematicSeparator = "://"
let placeholderSeparator = "__TEMP_REPLACE__"
let serverUrlWithoutPrefix = serverUrl.replacingOccurrences(of: problematicSeparator, with: placeholderSeparator)
var splitServerUrl = serverUrlWithoutPrefix.split(separator: "/")
let directoryItemFileName = String(splitServerUrl.removeLast())
let directoryItemServerUrl = splitServerUrl.joined(separator: "/").replacingOccurrences(of: placeholderSeparator, with: problematicSeparator)
if let metadata = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@ AND directory == true", account, directoryItemServerUrl, directoryItemFileName).first {
return NextcloudItemMetadataTable(value: metadata)
}
return nil
}
func directoryMetadata(ocId: String) -> NextcloudDirectoryMetadataTable? {
if let metadata = ncDatabase().objects(NextcloudDirectoryMetadataTable.self).filter("ocId == %@", ocId).first {
return NextcloudDirectoryMetadataTable(value: metadata)
}
return nil
func childDirectoriesForDirectory(_ directoryMetadata: NextcloudItemMetadataTable) -> [NextcloudItemMetadataTable] {
let directoryServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("serverUrl BEGINSWITH %@ AND ocId != %@ AND directory == true", directoryServerUrl, directoryMetadata.account)
return sortedItemMetadatas(metadatas)
}
private func sortedDirectoryMetadatas(_ metadatas: Results<NextcloudDirectoryMetadataTable>) -> [NextcloudDirectoryMetadataTable] {
let sortedMetadatas = metadatas.sorted(byKeyPath: "serverUrl", ascending: true)
return Array(sortedMetadatas.map { NextcloudDirectoryMetadataTable(value: $0) })
}
func childDirectoriesForDirectory(_ directoryMetadata: NextcloudDirectoryMetadataTable) -> [NextcloudDirectoryMetadataTable] {
let metadatas = ncDatabase().objects(NextcloudDirectoryMetadataTable.self).filter("serverUrl BEGINSWITH %@ AND ocId != %@", directoryMetadata.serverUrl, directoryMetadata.account)
return sortedDirectoryMetadatas(metadatas)
}
func parentDirectoryMetadataForItem(_ itemMetadata: NextcloudItemMetadataTable) -> NextcloudDirectoryMetadataTable? {
func parentDirectoryMetadataForItem(_ itemMetadata: NextcloudItemMetadataTable) -> NextcloudItemMetadataTable? {
return directoryMetadata(account: itemMetadata.account, serverUrl: itemMetadata.serverUrl)
}
func directoryMetadatas(account: String) -> [NextcloudDirectoryMetadataTable] {
let metadatas = ncDatabase().objects(NextcloudDirectoryMetadataTable.self).filter("account == %@", account)
return sortedDirectoryMetadatas(metadatas)
}
func directoryMetadatas(account: String, parentDirectoryServerUrl: String) -> [NextcloudDirectoryMetadataTable] {
let metadatas = ncDatabase().objects(NextcloudDirectoryMetadataTable.self).filter("account == %@ AND parentDirectoryServerUrl == %@", account, parentDirectoryServerUrl)
return sortedDirectoryMetadatas(metadatas)
}
private func processDirectoryMetadatasToDelete(databaseToWriteTo: Realm,
existingDirectoryMetadatas: Results<NextcloudDirectoryMetadataTable>,
updatedDirectoryMetadatas: [NextcloudDirectoryMetadataTable]) {
for existingMetadata in existingDirectoryMetadatas {
guard !updatedDirectoryMetadatas.contains(where: { $0.ocId == existingMetadata.ocId }),
let metadataToDelete = directoryMetadata(ocId: existingMetadata.ocId) else { continue }
Logger.ncFilesDatabase.debug("Deleting directory metadata during update. ocID: \(existingMetadata.ocId, privacy: .public), etag: \(existingMetadata.etag, privacy: .public), serverUrl: \(existingMetadata.serverUrl)")
self.deleteDirectoryAndSubdirectoriesMetadata(ocId: metadataToDelete.ocId)
}
}
private func processDirectoryMetadatasToUpdate(databaseToWriteTo: Realm,
existingDirectoryMetadatas: Results<NextcloudDirectoryMetadataTable>,
updatedDirectoryMetadatas: [NextcloudDirectoryMetadataTable]) {
assert(databaseToWriteTo.isInWriteTransaction)
for updatedMetadata in updatedDirectoryMetadatas {
if let existingMetadata = existingDirectoryMetadatas.first(where: { $0.ocId == updatedMetadata.ocId }) {
if !existingMetadata.isInSameRemoteState(updatedMetadata) {
databaseToWriteTo.add(NextcloudDirectoryMetadataTable(value: updatedMetadata), update: .all)
Logger.ncFilesDatabase.debug("Updated existing directory metadata. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), serverUrl: \(updatedMetadata.serverUrl)")
}
// Don't update under other circumstances in which the metadata already exists
} else { // This is a new metadata
databaseToWriteTo.add(NextcloudDirectoryMetadataTable(value: updatedMetadata), update: .all)
Logger.ncFilesDatabase.debug("Created new directory metadata during update. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), serverUrl: \(updatedMetadata.serverUrl)")
}
}
}
func updateDirectoryMetadatas(account: String, parentDirectoryServerUrl: String, updatedDirectoryMetadatas: [NextcloudDirectoryMetadataTable]) {
let database = ncDatabase()
let existingDirectoryMetadatas = ncDatabase().objects(NextcloudDirectoryMetadataTable.self).filter("account == %@ AND parentDirectoryServerUrl == %@", account, parentDirectoryServerUrl)
// Actual db writing handled internally
processDirectoryMetadatasToDelete(databaseToWriteTo: database,
existingDirectoryMetadatas: existingDirectoryMetadatas,
updatedDirectoryMetadatas: updatedDirectoryMetadatas)
do {
try database.write {
processDirectoryMetadatasToUpdate(databaseToWriteTo: database,
existingDirectoryMetadatas: existingDirectoryMetadatas,
updatedDirectoryMetadatas: updatedDirectoryMetadatas)
}
} catch let error {
Logger.ncFilesDatabase.error("Could not update directory metadatas, received error: \(error.localizedDescription)")
}
}
func directoryMetadataFromItemMetadata(directoryItemMetadata: NextcloudItemMetadataTable, recordEtag: Bool = false) -> NextcloudDirectoryMetadataTable {
var newDirectoryMetadata = NextcloudDirectoryMetadataTable()
let directoryOcId = directoryItemMetadata.ocId
if let existingDirectoryMetadata = directoryMetadata(ocId: directoryOcId) {
newDirectoryMetadata = existingDirectoryMetadata
func directoryMetadata(ocId: String) -> NextcloudItemMetadataTable? {
if let metadata = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first {
return NextcloudItemMetadataTable(value: metadata)
}
if recordEtag {
newDirectoryMetadata.etag = directoryItemMetadata.etag
}
newDirectoryMetadata.ocId = directoryOcId
newDirectoryMetadata.fileId = directoryItemMetadata.fileId
newDirectoryMetadata.parentDirectoryServerUrl = directoryItemMetadata.serverUrl
newDirectoryMetadata.serverUrl = directoryItemMetadata.serverUrl + "/" + directoryItemMetadata.fileNameView
newDirectoryMetadata.account = directoryItemMetadata.account
newDirectoryMetadata.e2eEncrypted = directoryItemMetadata.e2eEncrypted
newDirectoryMetadata.favorite = directoryItemMetadata.favorite
newDirectoryMetadata.permissions = directoryItemMetadata.permissions
return newDirectoryMetadata
return nil
}
func updateDirectoryMetadatasFromItemMetadatas(account: String, parentDirectoryServerUrl: String, updatedDirectoryItemMetadatas: [NextcloudItemMetadataTable], recordEtag: Bool = false) {
var updatedDirMetadatas: [NextcloudDirectoryMetadataTable] = []
for directoryItemMetadata in updatedDirectoryItemMetadatas {
let newDirectoryMetadata = directoryMetadataFromItemMetadata(directoryItemMetadata: directoryItemMetadata, recordEtag: recordEtag)
updatedDirMetadatas.append(newDirectoryMetadata)
}
updateDirectoryMetadatas(account: account, parentDirectoryServerUrl: parentDirectoryServerUrl, updatedDirectoryMetadatas: updatedDirMetadatas)
func directoryMetadatas(account: String) -> [NextcloudItemMetadataTable] {
let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND directory == true", account)
return sortedItemMetadatas(metadatas)
}
func addDirectoryMetadata(_ metadata: NextcloudDirectoryMetadataTable) {
let database = ncDatabase()
do {
try database.write {
database.add(metadata, update: .all)
Logger.ncFilesDatabase.debug("Added new directory metadata. ocId: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), serverUrl: \(metadata.serverUrl)")
}
} catch let error {
Logger.ncFilesDatabase.error("Could not add new directory metadata. ocId: \(metadata.ocId, privacy: .public), etag: \(metadata.etag, privacy: .public), serverUrl: \(metadata.serverUrl), received error: \(error.localizedDescription, privacy: .public)")
}
func directoryMetadatas(account: String, parentDirectoryServerUrl: String) -> [NextcloudItemMetadataTable] {
let metadatas = ncDatabase().objects(NextcloudItemMetadataTable.self).filter("account == %@ AND parentDirectoryServerUrl == %@ AND directory == true", account, parentDirectoryServerUrl)
return sortedItemMetadatas(metadatas)
}
// Deletes all metadatas related to the info of the directory provided
func deleteDirectoryAndSubdirectoriesMetadata(ocId: String) {
let database = ncDatabase()
guard let directoryMetadata = database.objects(NextcloudDirectoryMetadataTable.self).filter("ocId == %@", ocId).first else {
guard let directoryMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first else {
Logger.ncFilesDatabase.error("Could not find directory metadata for ocId \(ocId, privacy: .public). Not proceeding with deletion")
return
}
let results = database.objects(NextcloudDirectoryMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, directoryMetadata.serverUrl)
let directoryUrlPath = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
let results = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, directoryUrlPath)
for result in results {
deleteItemMetadata(ocId: result.ocId)
@ -455,11 +352,11 @@ class NextcloudFilesDatabaseManager : NSObject {
do {
try database.write {
Logger.ncFilesDatabase.debug("Deleting root directory metadata in recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryMetadata.etag, privacy: .public), serverUrl: \(directoryMetadata.serverUrl)")
Logger.ncFilesDatabase.debug("Deleting root directory metadata in recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryMetadata.etag, privacy: .public), serverUrl: \(directoryUrlPath)")
database.delete(results)
}
} catch let error {
Logger.ncFilesDatabase.error("Could not delete root directory metadata in recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryMetadata.etag, privacy: .public), serverUrl: \(directoryMetadata.serverUrl), received error: \(error.localizedDescription, privacy: .public)")
Logger.ncFilesDatabase.error("Could not delete root directory metadata in recursive delete. ocID: \(directoryMetadata.ocId, privacy: .public), etag: \(directoryMetadata.etag, privacy: .public), serverUrl: \(directoryUrlPath), received error: \(error.localizedDescription, privacy: .public)")
}
}
@ -468,25 +365,19 @@ class NextcloudFilesDatabaseManager : NSObject {
let database = ncDatabase()
do {
guard let directoryMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first else {
Logger.ncFilesDatabase.error("Could not find a directory with ocID \(ocId, privacy: .public), cannot proceed with recursive renaming")
return
}
let oldServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
let childItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, oldServerUrl)
renameItemMetadata(ocId: ocId, newServerUrl: newServerUrl, newFileName: newFileName)
Logger.ncFilesDatabase.debug("Renamed root renaming directory")
try database.write {
guard let directoryTableResult = database.objects(NextcloudDirectoryMetadataTable.self).filter("ocId == %@", ocId).first,
let directoryItemResult = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@", ocId).first else {
Logger.ncFilesDatabase.error("Could not find a directory with ocID \(ocId, privacy: .public), cannot proceed with recursive renaming")
return
}
let oldServerUrl = directoryTableResult.serverUrl
let childItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryTableResult.account, oldServerUrl)
let childDirectoryResults = database.objects(NextcloudDirectoryMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryTableResult.account, oldServerUrl)
directoryTableResult.serverUrl = newServerUrl
database.add(directoryTableResult, update: .all)
directoryItemResult.fileName = newFileName
directoryItemResult.fileNameView = newFileName
database.add(directoryItemResult, update: .all)
Logger.ncFilesDatabase.debug("Renamed root renaming directory at \(oldServerUrl) to \(newServerUrl)")
for childItem in childItemResults {
let oldServerUrl = childItem.serverUrl
let movedServerUrl = oldServerUrl.replacingOccurrences(of: oldServerUrl, with: newServerUrl)
@ -494,17 +385,6 @@ class NextcloudFilesDatabaseManager : NSObject {
database.add(childItem, update: .all)
Logger.ncFilesDatabase.debug("Moved childItem at \(oldServerUrl) to \(movedServerUrl)")
}
for childDirectory in childDirectoryResults {
let oldServerUrl = childDirectory.serverUrl
let oldParentServerUrl = childDirectory.parentDirectoryServerUrl
let movedServerUrl = oldServerUrl.replacingOccurrences(of: oldServerUrl, with: newServerUrl)
let movedParentServerUrl = oldServerUrl.replacingOccurrences(of: oldParentServerUrl, with: newServerUrl)
childDirectory.serverUrl = movedServerUrl
childDirectory.parentDirectoryServerUrl = movedParentServerUrl
database.add(childDirectory, update: .all)
Logger.ncFilesDatabase.debug("Moved childDirectory at \(oldServerUrl) to \(movedServerUrl)")
}
}
} catch let error {
Logger.ncFilesDatabase.error("Could not rename directory metadata with ocId: \(ocId, privacy: .public) to new serverUrl: \(newServerUrl), received error: \(error.localizedDescription, privacy: .public)")

Просмотреть файл

@ -113,8 +113,10 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
dispatchGroup.enter() // Add to outer counter
dispatchQueue.async {
let directoryServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
guard serverError == nil else {
Logger.enumeration.info("Skipping enumeration of directory for working set: \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) as we have an error.")
Logger.enumeration.info("Skipping enumeration of directory for working set: \(directoryServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) as we have an error.")
dispatchGroup.leave()
return;
}
@ -122,9 +124,9 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
let currentNetworkTaskDispatchGroup = DispatchGroup() // To make this serial queue wait until this task is done
currentNetworkTaskDispatchGroup.enter()
FileProviderEnumerator.readServerUrl(directoryMetadata.serverUrl, ncAccount: self.ncAccount, ncKit: self.ncKit) { metadatas, _, _, _, readError in
FileProviderEnumerator.readServerUrl(directoryServerUrl, ncAccount: self.ncAccount, ncKit: self.ncKit) { metadatas, _, _, _, readError in
guard readError == nil else {
Logger.enumeration.error("Finishing enumeration of working set directory \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) with error \(readError!.localizedDescription, privacy: .public)")
Logger.enumeration.error("Finishing enumeration of working set directory \(directoryServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) with error \(readError!.localizedDescription, privacy: .public)")
let nkError = NKError(error: readError!)
if nkError.isUnauthenticatedError || nkError.isCouldntConnectError {
@ -140,7 +142,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
if let metadatas = metadatas {
allMetadatas += metadatas
} else {
allMetadatas += dbManager.itemMetadatas(account: self.ncAccount.ncKitAccount, serverUrl: directoryMetadata.serverUrl)
allMetadatas += dbManager.itemMetadatas(account: self.ncAccount.ncKitAccount, serverUrl: directoryServerUrl)
}
currentNetworkTaskDispatchGroup.leave()
@ -419,9 +421,8 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
private static func fullRecursiveScan(ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool, completionHandler: @escaping(_ newMetadatas: [NextcloudItemMetadataTable], _ updatedMetadatas: [NextcloudItemMetadataTable], _ deletedMetadatas: [NextcloudItemMetadataTable]) -> Void) {
let rootContainerDirectoryMetadata = NextcloudDirectoryMetadataTable()
rootContainerDirectoryMetadata.serverUrl = ncAccount.davFilesUrl
rootContainerDirectoryMetadata.account = ncAccount.ncKitAccount
let rootContainerDirectoryMetadata = NextcloudItemMetadataTable()
rootContainerDirectoryMetadata.directory = true
rootContainerDirectoryMetadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue
// Create a serial dispatch queue
@ -436,7 +437,9 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
}
}
private static func scanRecursively(_ directoryMetadata: NextcloudDirectoryMetadataTable, ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool) -> (metadatas: [NextcloudItemMetadataTable], newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], deletedMetadatas: [NextcloudItemMetadataTable]) {
private static func scanRecursively(_ directoryMetadata: NextcloudItemMetadataTable, ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool) -> (metadatas: [NextcloudItemMetadataTable], newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], deletedMetadatas: [NextcloudItemMetadataTable]) {
assert(directoryMetadata.directory, "Can only recursively scan a directory.")
var allMetadatas: [NextcloudItemMetadataTable] = []
var allNewMetadatas: [NextcloudItemMetadataTable] = []
@ -448,8 +451,12 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
dispatchGroup.enter()
Logger.enumeration.debug("About to read: \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash))")
FileProviderEnumerator.readServerUrl(directoryMetadata.serverUrl, ncAccount: ncAccount, ncKit: ncKit, stopAtMatchingEtags: scanChangesOnly) { metadatas, newMetadatas, updatedMetadatas, deletedMetadatas, readError in
let itemServerUrl = directoryMetadata.ocId == NSFileProviderItemIdentifier.rootContainer.rawValue ?
ncAccount.davFilesUrl : directoryMetadata.serverUrl + "/" + directoryMetadata.fileName
Logger.enumeration.debug("About to read: \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash))")
FileProviderEnumerator.readServerUrl(itemServerUrl, ncAccount: ncAccount, ncKit: ncKit, stopAtMatchingEtags: scanChangesOnly) { metadatas, newMetadatas, updatedMetadatas, deletedMetadatas, readError in
if readError != nil {
let nkReadError = NKError(error: readError!)
@ -457,7 +464,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
// Is the error is that we have found matching etags on this item, then ignore it
// if we are doing a full rescan
guard nkReadError.isNoChangesError && scanChangesOnly else {
Logger.enumeration.error("Finishing enumeration of changes at \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) with \(readError!.localizedDescription, privacy: .public)")
Logger.enumeration.error("Finishing enumeration of changes at \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) with \(readError!.localizedDescription, privacy: .public)")
if nkReadError.isNotFoundError {
Logger.enumeration.info("404 error means item no longer exists. Deleting metadata and reporting as deletion without error")
@ -479,30 +486,30 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
}
}
Logger.enumeration.info("Finished reading serverUrl: \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
Logger.enumeration.info("Finished reading serverUrl: \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
if let metadatas = metadatas {
allMetadatas += metadatas
} else {
Logger.enumeration.warning("WARNING: Nil metadatas received for reading of changes at \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
Logger.enumeration.warning("WARNING: Nil metadatas received for reading of changes at \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
}
if let newMetadatas = newMetadatas {
allNewMetadatas += newMetadatas
} else {
Logger.enumeration.warning("WARNING: Nil new metadatas received for reading of changes at \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
Logger.enumeration.warning("WARNING: Nil new metadatas received for reading of changes at \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
}
if let updatedMetadatas = updatedMetadatas {
allUpdatedMetadatas += updatedMetadatas
} else {
Logger.enumeration.warning("WARNING: Nil updated metadatas received for reading of changes at \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
Logger.enumeration.warning("WARNING: Nil updated metadatas received for reading of changes at \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
}
if let deletedMetadatas = deletedMetadatas {
allDeletedMetadatas += deletedMetadatas
} else {
Logger.enumeration.warning("WARNING: Nil deleted metadatas received for reading of changes at \(directoryMetadata.serverUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
Logger.enumeration.warning("WARNING: Nil deleted metadatas received for reading of changes at \(itemServerUrl, privacy: OSLogPrivacy.auto(mask: .hash)) for user: \(ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
}
dispatchGroup.leave()
@ -510,7 +517,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
dispatchGroup.wait()
var updatedDirectories: [NextcloudDirectoryMetadataTable] = []
var updatedDirectories: [NextcloudItemMetadataTable] = []
for updatedMetadata in allUpdatedMetadatas {
if updatedMetadata.directory {
guard let directoryMetadata = dbManager.directoryMetadata(ocId: updatedMetadata.ocId) else {
@ -600,18 +607,9 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
// We have now scanned this directory's contents, so update with etag in order to not check again if not needed
// unless it's the root container
if serverUrl != ncAccount.davFilesUrl {
let directoryItemMetadata = dbManager.directoryMetadataFromItemMetadata(directoryItemMetadata: directoryMetadata, recordEtag: true)
dbManager.addDirectoryMetadata(directoryItemMetadata)
dbManager.addItemMetadata(directoryMetadata)
}
// STORE ETAG-LESS DIRECTORY METADATA FOR CHILD DIRECTORIES
// Since we haven't scanned the contents of the child directories, don't record their itemMetadata etags in the directory tables
// This will delete database records for directories that we did not get from the readFileOrFolder (indicating they were deleted)
// as well as deleting the records for all the children contained by the directories.
// TODO: Find a way to detect if files have been moved rather than deleted and change the metadata server urls, move the materialised files
dbManager.updateDirectoryMetadatasFromItemMetadatas(account: ncKitAccount, parentDirectoryServerUrl: serverUrl, updatedDirectoryItemMetadatas: childDirectoriesMetadata)
// TODO: Notify working set changed if new folders found
dbManager.updateItemMetadatas(account: ncKitAccount, serverUrl: serverUrl, updatedMetadatas: metadatas) { newMetadatas, updatedMetadatas, deletedMetadatas in
completionHandler(metadatas, newMetadatas, updatedMetadatas, deletedMetadatas, nil)
}

Просмотреть файл

@ -232,28 +232,22 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
return Progress()
}
var parentItemMetadata: NextcloudDirectoryMetadataTable?
var parentItemServerUrl: String
if parentItemIdentifier == .rootContainer {
let rootMetadata = NextcloudDirectoryMetadataTable()
rootMetadata.account = ncAccount.ncKitAccount
rootMetadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue
rootMetadata.serverUrl = ncAccount.davFilesUrl
parentItemMetadata = rootMetadata
parentItemServerUrl = ncAccount.davFilesUrl
} else {
parentItemMetadata = dbManager.directoryMetadata(ocId: parentItemIdentifier.rawValue)
}
guard let parentItemMetadata = dbManager.directoryMetadata(ocId: parentItemIdentifier.rawValue) else {
Logger.fileProviderExtension.error("Not creating item: \(itemTemplate.itemIdentifier.rawValue, privacy: .public), could not find metadata for parentItemIdentifier \(parentItemIdentifier.rawValue, privacy: .public)")
completionHandler(itemTemplate, NSFileProviderItemFields(), false, NSFileProviderError(.noSuchItem))
return Progress()
}
guard let parentItemMetadata = parentItemMetadata else {
Logger.fileProviderExtension.error("Not creating item: \(itemTemplate.itemIdentifier.rawValue, privacy: .public), could not find metadata for parentItemIdentifier \(parentItemIdentifier.rawValue, privacy: .public)")
completionHandler(itemTemplate, NSFileProviderItemFields(), false, NSFileProviderError(.noSuchItem))
return Progress()
parentItemServerUrl = parentItemMetadata.serverUrl + "/" + parentItemMetadata.fileName
}
let fileNameLocalPath = url?.path ?? ""
let newServerUrlFileName = parentItemMetadata.serverUrl + "/" + itemTemplate.filename
let newServerUrlFileName = parentItemServerUrl + "/" + itemTemplate.filename
Logger.fileProviderExtension.debug("About to upload item with identifier: \(itemTemplate.itemIdentifier.rawValue, privacy: .public) of type: \(itemTemplate.contentType?.identifier ?? "UNKNOWN") (is folder: \(itemTemplateIsFolder ? "yes" : "no") and filename: \(itemTemplate.filename) to server url: \(newServerUrlFileName, privacy: OSLogPrivacy.auto(mask: .hash)) with contents located at: \(fileNameLocalPath, privacy: OSLogPrivacy.auto(mask: .hash))")
@ -275,8 +269,6 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
DispatchQueue.global().async {
dbManager.convertNKFilesFromDirectoryReadToItemMetadatas(files, account: account) { directoryMetadata, childDirectoriesMetadata, metadatas in
let newDirectoryMetadata = dbManager.directoryMetadataFromItemMetadata(directoryItemMetadata: directoryMetadata)
dbManager.addDirectoryMetadata(newDirectoryMetadata)
dbManager.addItemMetadata(directoryMetadata)
let fpItem = FileProviderItem(metadata: directoryMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: self.ncKit)
@ -323,7 +315,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
newMetadata.size = size
newMetadata.contentType = itemTemplate.contentType?.preferredMIMEType ?? ""
newMetadata.directory = itemTemplateIsFolder
newMetadata.serverUrl = parentItemMetadata.serverUrl
newMetadata.serverUrl = parentItemServerUrl
newMetadata.session = ""
newMetadata.sessionError = ""
newMetadata.sessionTaskIdentifier = 0
@ -362,28 +354,22 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
Logger.fileProviderExtension.warning("Modification for item: \(item.itemIdentifier.rawValue, privacy: .public) may already exist")
}
var parentItemMetadata: NextcloudDirectoryMetadataTable?
var parentItemServerUrl: String
if parentItemIdentifier == .rootContainer {
let rootMetadata = NextcloudDirectoryMetadataTable()
rootMetadata.account = ncAccount.ncKitAccount
rootMetadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue
rootMetadata.serverUrl = ncAccount.davFilesUrl
parentItemMetadata = rootMetadata
parentItemServerUrl = ncAccount.davFilesUrl
} else {
parentItemMetadata = dbManager.directoryMetadata(ocId: parentItemIdentifier.rawValue)
}
guard let parentItemMetadata = dbManager.directoryMetadata(ocId: parentItemIdentifier.rawValue) else {
Logger.fileProviderExtension.error("Not modifying item: \(item.itemIdentifier.rawValue, privacy: .public), could not find metadata for parentItemIdentifier \(parentItemIdentifier.rawValue, privacy: .public)")
completionHandler(item, [], false, NSFileProviderError(.noSuchItem))
return Progress()
}
guard let parentItemMetadata = parentItemMetadata else {
Logger.fileProviderExtension.error("Not modifying item: \(item.itemIdentifier.rawValue, privacy: .public), could not find metadata for parentItemIdentifier \(parentItemIdentifier.rawValue, privacy: .public)")
completionHandler(item, [], false, NSFileProviderError(.noSuchItem))
return Progress()
parentItemServerUrl = parentItemMetadata.serverUrl + "/" + parentItemMetadata.fileName
}
let fileNameLocalPath = newContents?.path ?? ""
let newServerUrlFileName = parentItemMetadata.serverUrl + "/" + item.filename
let newServerUrlFileName = parentItemServerUrl + "/" + item.filename
Logger.fileProviderExtension.debug("About to upload modified item with identifier: \(item.itemIdentifier.rawValue, privacy: .public) of type: \(item.contentType?.identifier ?? "UNKNOWN") (is folder: \(itemTemplateIsFolder ? "yes" : "no") and filename: \(item.filename, privacy: OSLogPrivacy.auto(mask: .hash)) to server url: \(newServerUrlFileName, privacy: OSLogPrivacy.auto(mask: .hash)) with contents located at: \(fileNameLocalPath, privacy: OSLogPrivacy.auto(mask: .hash))")
@ -427,7 +413,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
if itemTemplateIsFolder {
dbManager.renameDirectoryAndPropagateToChildren(ocId: ocId, newServerUrl: newServerUrlFileName, newFileName: item.filename)
} else {
dbManager.renameItemMetadata(ocId: ocId, newServerUrl: parentItemMetadata.serverUrl, newFileName: item.filename)
dbManager.renameItemMetadata(ocId: ocId, newServerUrl: parentItemServerUrl, newFileName: item.filename)
}
guard let newMetadata = dbManager.itemMetadataFromOcId(ocId) else {
@ -519,7 +505,7 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
newMetadata.size = size
newMetadata.contentType = item.contentType?.preferredMIMEType ?? ""
newMetadata.directory = itemTemplateIsFolder
newMetadata.serverUrl = parentItemMetadata.serverUrl
newMetadata.serverUrl = parentItemServerUrl
newMetadata.session = ""
newMetadata.sessionError = ""
newMetadata.sessionTaskIdentifier = 0
@ -631,6 +617,15 @@ class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension, NKComm
materialisedEnumerator.enumerateItems(for: materialisedObserver, startingAt: startingPage)
}
func signalEnumerator(completionHandler: @escaping(_ error: Error?) -> Void) {
guard let fpManager = NSFileProviderManager(for: self.domain) else {
Logger.fileProviderExtension.error("Could not get file provider manager for domain, could not signal enumerator. This might lead to future conflicts.")
return
}
fpManager.signalEnumerator(for: .workingSet, completionHandler: completionHandler)
}
// MARK: Nextcloud desktop client communication
func sendFileProviderDomainIdentifier() {
let command = "FILE_PROVIDER_DOMAIN_IDENTIFIER_REQUEST_REPLY"

Просмотреть файл

@ -16,7 +16,7 @@ import Foundation
import FileProvider
class NextcloudAccount: NSObject {
let webDavFilesUrlSuffix: String = "/remote.php/dav/files/"
private let webDavFilesUrlSuffix: String = "/remote.php/dav/files/"
let username, password, ncKitAccount, serverUrl, davFilesUrl: String
init(user: String, serverUrl: String, password: String) {

Просмотреть файл

@ -12,7 +12,6 @@
5307A6EB2965DB8D001E0C6A /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6EA2965DB8D001E0C6A /* RealmSwift */; };
5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */; };
5318AD9129BF42FB00CBB71C /* NextcloudItemMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */; };
5318AD9329BF432B00CBB71C /* NextcloudDirectoryMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9229BF432B00CBB71C /* NextcloudDirectoryMetadataTable.swift */; };
5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */; };
5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */; };
5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */; };
@ -137,7 +136,6 @@
/* Begin PBXFileReference section */
5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudFilesDatabaseManager.swift; sourceTree = "<group>"; };
5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudItemMetadataTable.swift; sourceTree = "<group>"; };
5318AD9229BF432B00CBB71C /* NextcloudDirectoryMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudDirectoryMetadataTable.swift; sourceTree = "<group>"; };
5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudLocalFileMetadataTable.swift; sourceTree = "<group>"; };
5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderMaterialisedEnumerationObserver.swift; sourceTree = "<group>"; };
5318AD9829BF58D000CBB71C /* NKError+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKError+Extensions.swift"; sourceTree = "<group>"; };
@ -219,7 +217,6 @@
isa = PBXGroup;
children = (
5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */,
5318AD9229BF432B00CBB71C /* NextcloudDirectoryMetadataTable.swift */,
5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */,
5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */,
);
@ -563,7 +560,6 @@
5352E85B29B7BFE6002CE85C /* Progress+Extensions.swift in Sources */,
536EFC36295E3C1100F4CB13 /* NextcloudAccount.swift in Sources */,
538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */,
5318AD9329BF432B00CBB71C /* NextcloudDirectoryMetadataTable.swift in Sources */,
536EFBF7295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift in Sources */,
5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */,
5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */,