Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 2 additions & 6 deletions Sources/NextcloudKit/NKCommon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ public struct NKCommon: Sendable {
public let groupDefaultsUnavailable = "Unavailable"
public let groupDefaultsToS = "ToS"



// MARK: - Init

init() { }
Expand Down Expand Up @@ -200,11 +198,11 @@ public struct NKCommon: Sendable {

// MARK: - Server Error GroupDefaults

public func appendServerErrorAccount(_ account: String, errorCode: Int) {
public func appendServerErrorAccount(_ account: String, errorCode: Int) async {
guard let groupDefaults = UserDefaults(suiteName: groupIdentifier) else {
return
}
let capabilities = NKCapabilities.shared.getCapabilitiesBlocking(for: account)
let capabilities = await NKCapabilities.shared.getCapabilities(for: account)

/// Unavailable
if errorCode == 503 {
Expand Down Expand Up @@ -239,8 +237,6 @@ public struct NKCommon: Sendable {
return "\(identifier).\(account)"
}



public func getStandardHeaders(account: String, options: NKRequestOptions? = nil) -> HTTPHeaders? {
guard let session = nksessions.session(forAccount: account) else {
return nil
Expand Down
4 changes: 3 additions & 1 deletion Sources/NextcloudKit/NKMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ final class NKMonitor: EventMonitor, Sendable {
let headerCheckInterceptor = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerCheckInterceptor],
headerCheckInterceptor.lowercased() == "true",
let account = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerAccount] {
nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode)
Task {
await nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode)
}
}

DispatchQueue.global(qos: .utility).async {
Expand Down
41 changes: 3 additions & 38 deletions Sources/NextcloudKit/NextcloudKit+Capabilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ public extension NextcloudKit {
capabilities.termsOfService = json.termsOfService?.enabled ?? false

// Persist capabilities in shared store
await NKCapabilities.shared.appendCapabilitiesAsync(for: account, capabilities: capabilities)
await NKCapabilities.shared.setCapabilities(for: account, capabilities: capabilities)
return capabilities
} catch {
nkLog(error: "Could not decode json capabilities: \(error.localizedDescription)")
Expand Down Expand Up @@ -490,49 +490,14 @@ final public class NKCapabilities: Sendable {

// MARK: - Public API

public func appendCapabilitiesAsync(for account: String, capabilities: Capabilities) async {
public func setCapabilities(for account: String, capabilities: Capabilities) async {
await store.set(account, value: capabilities)
}

/// Synchronously stores capabilities for the given account.
/// Blocks the current thread until the async actor completes.
/// Use only outside of async/actor contexts.
public func appendCapabilitiesBlocking(for account: String, capabilities: Capabilities) {
let group = DispatchGroup()

group.enter()
Task.detached(priority: .userInitiated) {
await self.store.set(account, value: capabilities)
group.leave()
}

group.wait()
}

public func getCapabilitiesAsync(for account: String?) async -> Capabilities {
public func getCapabilities(for account: String?) async -> Capabilities {
guard let account else {
return Capabilities()
}
return await store.get(account) ?? Capabilities()
}

/// Synchronously retrieves capabilities for the given account.
/// Blocks the current thread until the async actor returns.
/// Use only outside the Swift async context (never from another actor or async function).
public func getCapabilitiesBlocking(for account: String?) -> Capabilities {
guard let account else {
return Capabilities()
}
let group = DispatchGroup()
var result: Capabilities?

group.enter()
Task.detached(priority: .userInitiated) {
result = await self.store.get(account)
group.leave()
}

group.wait()
return result ?? Capabilities()
}
}
10 changes: 5 additions & 5 deletions Sources/NextcloudKit/NextcloudKit+NCText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ public extension NextcloudKit {
Task {
do {
let (editors, creators) = try NKEditorDetailsConverter.from(data: responseData)
let capabilities = await NKCapabilities.shared.getCapabilitiesAsync(for: account)
let capabilities = await NKCapabilities.shared.getCapabilities(for: account)
capabilities.directEditingEditors = editors
capabilities.directEditingCreators = creators
await NKCapabilities.shared.appendCapabilitiesAsync(for: account, capabilities: capabilities)
await NKCapabilities.shared.setCapabilities(for: account, capabilities: capabilities)

options.queue.async {
completion(account, editors, creators, response, .success)
Expand Down Expand Up @@ -206,10 +206,10 @@ public extension NextcloudKit {
let decoded = try JSONDecoder().decode(NKEditorTemplateResponse.self, from: data)
let templates = decoded.ocs.data.editors
// Update capabilities
let capabilities = await NKCapabilities.shared.getCapabilitiesAsync(for: account)
let capabilities = await NKCapabilities.shared.getCapabilities(for: account)
capabilities.directEditingTemplates = templates
await NKCapabilities.shared.appendCapabilitiesAsync(for: account, capabilities: capabilities)
await NKCapabilities.shared.setCapabilities(for: account, capabilities: capabilities)

options.queue.async { completion(account, templates, response, .success) }
} catch {
nkLog(error: "Failed to decode template list: \(error)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ public final class NKFilePropertyResolver {

public init() {}

public func resolve(inUTI: String, account: String) -> NKFileProperty {
public func resolve(inUTI: String, account: String) async -> NKFileProperty {
let fileProperty = NKFileProperty()
let typeIdentifier = inUTI as String
let capabilities = NKCapabilities.shared.getCapabilitiesBlocking(for: account)
let capabilities = await NKCapabilities.shared.getCapabilities(for: account)
let utiString = inUTI as String

// Preferred extension
Expand Down
41 changes: 2 additions & 39 deletions Sources/NextcloudKit/TypeIdentifiers/NKTypeIdentifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ public actor NKTypeIdentifiers {
private init() {}

// Resolves type info from file name and optional MIME type
public func getInternalType(fileName: String, mimeType inputMimeType: String, directory: Bool, account: String) -> NKTypeIdentifierCache {

public func getInternalType(fileName: String, mimeType inputMimeType: String, directory: Bool, account: String) async -> NKTypeIdentifierCache {
var ext = (fileName as NSString).pathExtension.lowercased()
var mimeType = inputMimeType
var classFile = ""
Expand Down Expand Up @@ -63,7 +62,7 @@ public actor NKTypeIdentifiers {
fileNameWithoutExt = fileName
ext = ""
} else {
let props = resolver.resolve(inUTI: typeIdentifier, account: account)
let props = await resolver.resolve(inUTI: typeIdentifier, account: account)
classFile = props.classFile.rawValue
iconName = props.iconName.rawValue
}
Expand Down Expand Up @@ -91,39 +90,3 @@ public actor NKTypeIdentifiers {
filePropertyCache.removeAll()
}
}

/// Helper class to access NKTypeIdentifiers from sync contexts (e.g. in legacy code or libraries).
public final class NKTypeIdentifiersHelper {
public static let shared = NKTypeIdentifiersHelper()

// Internal actor reference (uses NKTypeIdentifiers.shared by default)
private let actor: NKTypeIdentifiers

private init() {
self.actor = .shared
}

// Init with optional custom actor (useful for testing)
public init(actor: NKTypeIdentifiers = .shared) {
self.actor = actor
}

// Synchronously resolves file type info by calling the async actor inside a semaphore block.
public func getInternalTypeSync(fileName: String, mimeType: String, directory: Bool, account: String) -> NKTypeIdentifierCache {
var result: NKTypeIdentifierCache?
let semaphore = DispatchSemaphore(value: 0)

Task {
result = await actor.getInternalType(
fileName: fileName,
mimeType: mimeType,
directory: directory,
account: account
)
semaphore.signal()
}

semaphore.wait()
return result!
}
}
Loading