1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/*
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import FileProvider
import NextcloudFileProviderKit
import OSLog
extension FileProviderExtension: NSFileProviderCustomAction {
func performAction(
identifier actionIdentifier: NSFileProviderExtensionActionIdentifier,
onItemsWithIdentifiers itemIdentifiers: [NSFileProviderItemIdentifier],
completionHandler: @escaping ((any Error)?) -> Void
) -> Progress {
switch actionIdentifier.rawValue {
case "com.nextcloud.desktopclient.FileProviderExt.KeepDownloadedAction":
return performKeepDownloadedAction(
keepDownloaded: true,
onItemsWithIdentifiers: itemIdentifiers,
completionHandler: completionHandler
)
case "com.nextcloud.desktopclient.FileProviderExt.AutoEvictAction":
return performKeepDownloadedAction(
keepDownloaded: false,
onItemsWithIdentifiers: itemIdentifiers,
completionHandler: completionHandler
)
default:
logger.error("Unsupported action: \(actionIdentifier.rawValue)")
completionHandler(NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError))
return Progress()
}
}
private func performKeepDownloadedAction(
keepDownloaded: Bool,
onItemsWithIdentifiers itemIdentifiers: [NSFileProviderItemIdentifier],
completionHandler: @escaping ((any Error)?) -> Void
) -> Progress {
guard let ncAccount else {
logger.error("Not setting keep offline for items, account not set up yet.")
completionHandler(NSFileProviderError(.notAuthenticated))
return Progress()
}
guard let dbManager else {
logger.error("Not setting keep offline for items as database is unreachable.")
completionHandler(NSFileProviderError(.cannotSynchronize))
return Progress()
}
let progress = Progress()
// If there are no items, complete successfully immediately.
if itemIdentifiers.isEmpty {
logger.info("No items to process for keepDownloaded action.")
completionHandler(nil)
return progress
}
// Explicitly set totalUnitCount for clarity, though addChild with pendingUnitCount also defines this.
progress.totalUnitCount = Int64(itemIdentifiers.count)
Task {
let localNcKit = self.ncKit
let localDomain = self.domain
do {
try await withThrowingTaskGroup(of: Void.self) { group in
for identifier in itemIdentifiers {
group.addTask {
// This task processes one item.
guard let item = await Item.storedItem(
identifier: identifier,
account: ncAccount,
remoteInterface: localNcKit,
dbManager: dbManager,
log: self.log
) else {
throw NSError.fileProviderErrorForNonExistentItem(
withIdentifier: identifier
)
}
try await item.set(keepDownloaded: keepDownloaded, domain: localDomain)
}
}
for try await result in group {
progress.completedUnitCount = 1
}
}
logger.info("All items successfully processed for keepDownloaded=\(keepDownloaded)")
completionHandler(nil)
} catch let error {
logger.error("Error during keepDownloaded=\(keepDownloaded) action: \(error.localizedDescription)")
completionHandler(error)
}
}
return progress
}
}
|