Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let package = Package(
dependencies: [
.package(
url: "https://github.com/claucambra/NextcloudCapabilitiesKit.git",
.upToNextMajor(from: "2.1.2")
.upToNextMajor(from: "2.3.0")
),
.package(url: "https://github.com/nextcloud/NextcloudKit", from: "5.0.4"),
.package(url: "https://github.com/realm/realm-swift.git", exact: "20.0.1"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ extension Enumerator {
) {
let results = await self.scanRecursively(
Item.rootContainer(
account: account, remoteInterface: remoteInterface, dbManager: dbManager
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
).metadata,
account: account,
remoteInterface: remoteInterface,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ extension Enumerator {
remoteInterface: RemoteInterface,
dbManager: FilesDatabaseManager,
trashItems: [NKTrash]
) {
) async {
var newTrashedItems = [NSFileProviderItem]()

// NKTrash items do not have an etag ; we assume they cannot be modified while they are in
Expand All @@ -71,7 +71,8 @@ extension Enumerator {
parentItemIdentifier: .trashContainer,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
newTrashedItems.append(item)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ public class Enumerator: NSObject, NSFileProviderEnumerator {
return
}

Self.completeChangesObserver(
await Self.completeChangesObserver(
observer,
anchor: anchor,
account: account,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,6 @@ import NextcloudCapabilitiesKit
import NextcloudKit
import OSLog

fileprivate let CapabilitiesFetchInterval: TimeInterval = 30 * 60 // 30mins

actor RetrievedCapabilitiesActor {
static let shared: RetrievedCapabilitiesActor = {
let instance = RetrievedCapabilitiesActor()
return instance
}()
var data: [String: (capabilities: Capabilities, retrievedAt: Date)] = [:]

func setCapabilities(
forAccount account: String,
capabilities: Capabilities,
retrievedAt: Date = Date()
) async {
self.data[account] = (capabilities: capabilities, retrievedAt: retrievedAt)
}
}

extension NextcloudKit: RemoteInterface {

public func setDelegate(_ delegate: any NextcloudKitDelegate) {
Expand Down Expand Up @@ -398,6 +380,10 @@ extension NextcloudKit: RemoteInterface {
options: NKRequestOptions = .init(),
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }
) async -> (account: String, capabilities: Capabilities?, data: Data?, error: NKError) {
let ncKitAccount = account.ncKitAccount
await RetrievedCapabilitiesActor.shared.setOngoingFetch(
forAccount: ncKitAccount, ongoing: true
)
let result = await withCheckedContinuation { continuation in
getCapabilities(account: account.ncKitAccount, options: options, taskHandler: taskHandler) { account, data, error in
let capabilities: Capabilities? = {
Expand All @@ -407,6 +393,9 @@ extension NextcloudKit: RemoteInterface {
continuation.resume(returning: (account, capabilities, data?.data, error))
}
}
await RetrievedCapabilitiesActor.shared.setOngoingFetch(
forAccount: ncKitAccount, ongoing: false
)
if let capabilities = result.1 {
await RetrievedCapabilitiesActor.shared.setCapabilities(
forAccount: account.ncKitAccount, capabilities: capabilities
Expand All @@ -415,39 +404,6 @@ extension NextcloudKit: RemoteInterface {
return result
}

public func currentCapabilities(
account: Account,
options: NKRequestOptions = .init(),
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }
) async -> (account: String, capabilities: Capabilities?, data: Data?, error: NKError) {
let ncKitAccount = account.ncKitAccount
guard let lastRetrieval = await RetrievedCapabilitiesActor.shared.data[ncKitAccount],
lastRetrieval.retrievedAt.timeIntervalSince(Date()) > -CapabilitiesFetchInterval
else {
return await fetchCapabilities(
account: account, options: options, taskHandler: taskHandler
)
}
return (account.ncKitAccount, lastRetrieval.capabilities, nil, .success)
}

public func currentCapabilitiesSync(account: Account) -> Capabilities? {
let semaphore = DispatchSemaphore(value: 0)
var capabilities: Capabilities?
Task {
let (_, fetchedCapabilities, _, error) = await currentCapabilities(account: account)
if error != .success {
Logger
.init(subsystem: Logger.subsystem, category: "NextcloudKitRemoteInterface")
.error("Error during sync capabilities fetch: \(error.errorDescription, privacy: .public)")
}
capabilities = fetchedCapabilities
semaphore.signal()
}
semaphore.wait()
return capabilities
}

public func fetchUserProfile(
account: Account,
options: NKRequestOptions = .init(),
Expand Down
53 changes: 43 additions & 10 deletions Sources/NextcloudFileProviderKit/Interface/RemoteInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import FileProvider
import Foundation
import NextcloudCapabilitiesKit
import NextcloudKit
import OSLog


public enum EnumerateDepth: String {
case target = "0"
Expand Down Expand Up @@ -157,16 +159,6 @@ public protocol RemoteInterface {
taskHandler: @escaping (_ task: URLSessionTask) -> Void
) async -> (account: String, capabilities: Capabilities?, data: Data?, error: NKError)

// This method should result in fetches only after a certain period of time.
// Alternatively, it should only fetch when capabilities are guaranteed to have changed.
func currentCapabilities(
account: Account,
options: NKRequestOptions,
taskHandler: @escaping (_ task: URLSessionTask) -> Void
) async -> (account: String, capabilities: Capabilities?, data: Data?, error: NKError)

func currentCapabilitiesSync(account: Account) -> Capabilities?

func fetchUserProfile(
account: Account,
options: NKRequestOptions,
Expand All @@ -179,3 +171,44 @@ public protocol RemoteInterface {
taskHandler: @escaping (_ task: URLSessionTask) -> Void
) async -> AuthenticationAttemptResultState
}

public extension RemoteInterface {

private var logger: Logger {
Logger(subsystem: Logger.subsystem, category: "RemoteInterface")
}

func currentCapabilities(
account: Account,
options: NKRequestOptions = .init(),
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }
) async -> (account: String, capabilities: Capabilities?, data: Data?, error: NKError) {
let ncKitAccount = account.ncKitAccount
await RetrievedCapabilitiesActor.shared.awaitFetchCompletion(forAccount: ncKitAccount)
guard let lastRetrieval = await RetrievedCapabilitiesActor.shared.data[ncKitAccount],
lastRetrieval.retrievedAt.timeIntervalSince(Date()) > -CapabilitiesFetchInterval
else {
return await fetchCapabilities(
account: account, options: options, taskHandler: taskHandler
)
}
return (account.ncKitAccount, lastRetrieval.capabilities, nil, .success)
}

func supportsTrash(
account: Account,
options: NKRequestOptions = .init(),
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }
) async -> Bool {
var remoteSupportsTrash = false
let (_, capabilities, _, _) = await currentCapabilities(
account: account, options: .init(), taskHandler: { _ in }
)
if let filesCapabilities = capabilities?.files {
remoteSupportsTrash = filesCapabilities.undelete
} else {
logger.warning("Could not get capabilities, will assume trash is unavailable.")
}
return remoteSupportsTrash
}
}
14 changes: 9 additions & 5 deletions Sources/NextcloudFileProviderKit/Item/Item+Create.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)

return (fpItem, nil)
Expand Down Expand Up @@ -216,7 +217,8 @@ public extension Item {
parentItemIdentifier: itemTemplate.parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)

return (fpItem, nil)
Expand Down Expand Up @@ -412,7 +414,8 @@ public extension Item {
parentItemIdentifier: rootItem.parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
}

Expand Down Expand Up @@ -495,7 +498,7 @@ public extension Item {

let relativePath = parentItemRelativePath + "/" + itemTemplate.filename
guard ignoredFiles == nil || ignoredFiles?.isExcluded(relativePath) == false else {
return Item.createIgnored(
return await Item.createIgnored(
basedOn: itemTemplate,
parentItemRemotePath: parentItemRemotePath,
contents: url,
Expand Down Expand Up @@ -604,7 +607,8 @@ public extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
}

Expand Down
3 changes: 2 additions & 1 deletion Sources/NextcloudFileProviderKit/Item/Item+Fetch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ public extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)

return (localPath, fpItem, nil)
Expand Down
5 changes: 3 additions & 2 deletions Sources/NextcloudFileProviderKit/Item/Item+Ignored.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extension Item {
remoteInterface: RemoteInterface,
progress: Progress,
dbManager: FilesDatabaseManager
) -> (Item?, Error?) {
) async -> (Item?, Error?) {
let filename = itemTemplate.filename
Self.logger.info(
"""
Expand Down Expand Up @@ -60,7 +60,8 @@ extension Item {
parentItemIdentifier: itemTemplate.parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)

if #available(macOS 13.0, *) {
Expand Down
5 changes: 3 additions & 2 deletions Sources/NextcloudFileProviderKit/Item/Item+LockFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
),
returnError
)
Expand All @@ -167,7 +168,7 @@ extension Item {
)
assert(isLockFileName(filename), "Should not handle non-lock files here.")

guard let modifiedItem = modifyUnuploaded(
guard let modifiedItem = await modifyUnuploaded(
itemTarget: itemTarget,
baseVersion: baseVersion,
changedFields: changedFields,
Expand Down
11 changes: 7 additions & 4 deletions Sources/NextcloudFileProviderKit/Item/Item+Modify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ public extension Item {
parentItemIdentifier: newParentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
return (modifiedItem, nil)
}
Expand Down Expand Up @@ -224,7 +225,8 @@ public extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
return (modifiedItem, nil)
}
Expand Down Expand Up @@ -517,7 +519,8 @@ public extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
}

Expand Down Expand Up @@ -565,7 +568,7 @@ public extension Item {
Will delete locally with no remote effect.
"""
)
guard let modifiedIgnored = modifyUnuploaded(
guard let modifiedIgnored = await modifyUnuploaded(
itemTarget: itemTarget,
baseVersion: baseVersion,
changedFields: changedFields,
Expand Down
9 changes: 6 additions & 3 deletions Sources/NextcloudFileProviderKit/Item/Item+Trash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ extension Item {
parentItemIdentifier: .trashContainer,
account: account,
remoteInterface: modifiedItem.remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await modifiedItem.remoteInterface.supportsTrash(account: account)
)

// The server may have renamed the trashed file so we need to scan the entire trash
Expand Down Expand Up @@ -106,7 +107,8 @@ extension Item {
parentItemIdentifier: .trashContainer,
account: account,
remoteInterface: modifiedItem.remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await modifiedItem.remoteInterface.supportsTrash(account: account)
)

// Now we can directly update info on the child items
Expand Down Expand Up @@ -197,7 +199,8 @@ extension Item {
parentItemIdentifier: parentItemIdentifier,
account: account,
remoteInterface: modifiedItem.remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await modifiedItem.remoteInterface.supportsTrash(account: account)
), nil)
}

Expand Down
5 changes: 3 additions & 2 deletions Sources/NextcloudFileProviderKit/Item/Item+Unuploaded.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ extension Item {
forcedChunkSize: Int? = nil,
progress: Progress = .init(),
dbManager: FilesDatabaseManager
) -> Item? {
) async -> Item? {
var modifiedParentItemIdentifier = parentItemIdentifier
var modifiedMetadata = metadata

Expand Down Expand Up @@ -124,7 +124,8 @@ extension Item {
parentItemIdentifier: modifiedParentItemIdentifier,
account: account,
remoteInterface: remoteInterface,
dbManager: dbManager
dbManager: dbManager,
remoteSupportsTrash: await remoteInterface.supportsTrash(account: account)
)
}
}
Loading
Loading