From da91e22da186a501f3317f1048850a07647b70d5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 10:35:36 +0200 Subject: [PATCH 01/54] new Log Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 29 ++ .../NextcloudKit/Log/NKLogFileManager.swift | 266 ++++++++++++++++++ Sources/NextcloudKit/NKCommon.swift | 124 +------- Sources/NextcloudKit/NKInterceptor.swift | 21 +- Sources/NextcloudKit/NKMonitor.swift | 60 ++-- Sources/NextcloudKit/NextcloudKit+API.swift | 58 ---- .../NextcloudKit/NextcloudKit+Assistant.swift | 15 - .../NextcloudKit+AssistantV2.swift | 12 - .../NextcloudKit/NextcloudKit+Comments.swift | 20 -- .../NextcloudKit/NextcloudKit+Dashboard.swift | 6 - Sources/NextcloudKit/NextcloudKit+E2EE.swift | 33 --- .../NextcloudKit/NextcloudKit+FilesLock.swift | 3 - .../NextcloudKit+Groupfolders.swift | 3 - .../NextcloudKit/NextcloudKit+Hovercard.swift | 3 - .../NextcloudKit/NextcloudKit+Livephoto.swift | 3 - .../NextcloudKit/NextcloudKit+Logging.swift | 17 ++ Sources/NextcloudKit/NextcloudKit+Login.swift | 12 - .../NextcloudKit/NextcloudKit+NCText.swift | 12 - .../NextcloudKit+PushNotification.swift | 12 - .../NextcloudKit+RecommendedFiles.swift | 3 - .../NextcloudKit+Richdocuments.swift | 12 - .../NextcloudKit/NextcloudKit+Search.swift | 6 - Sources/NextcloudKit/NextcloudKit+Share.swift | 15 - .../NextcloudKit+ShareDownloadLimit.swift | 12 - .../NextcloudKit+TermsOfService.swift | 6 - .../NextcloudKit+UserStatus.swift | 21 -- .../NextcloudKit/NextcloudKit+WebDAV.swift | 27 -- Sources/NextcloudKit/NextcloudKit.swift | 12 +- .../NextcloudKit/NextcloudKitBackground.swift | 12 - .../NextcloudKitSessionDelegate.swift | 4 - 30 files changed, 362 insertions(+), 477 deletions(-) create mode 100644 Sources/NextcloudKit/Log/NKLog.swift create mode 100644 Sources/NextcloudKit/Log/NKLogFileManager.swift create mode 100644 Sources/NextcloudKit/NextcloudKit+Logging.swift diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift new file mode 100644 index 00000000..d7c0f18d --- /dev/null +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -0,0 +1,29 @@ +// +// NKLog.swift +// NextcloudKit +// +// Created by Marino Faggiana on 07/06/25. +// + +import Foundation + +/// Internal log helpers for use inside the NextcloudKit module. +internal func log(debug message: String) { + NKLogFileManager.shared.writeLog(debug: message) +} + +internal func log(info message: String) { + NKLogFileManager.shared.writeLog(info: message) +} + +internal func log(warning message: String) { + NKLogFileManager.shared.writeLog(warning: message) +} + +internal func log(error message: String) { + NKLogFileManager.shared.writeLog(error: message) +} + +internal func log(tag: String, message: String) { + NKLogFileManager.shared.writeLog(tag: tag, message: message) +} diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift new file mode 100644 index 00000000..a064b717 --- /dev/null +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -0,0 +1,266 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation +import Compression + +/// Defines the severity level of a log message. +public enum LogLevel: Int, Comparable { + case debug = 0 + case info = 1 + case warning = 2 + case error = 3 + + public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool { + return lhs.rawValue < rhs.rawValue + } +} + +/// A logger that writes log messages to a file in a subdirectory of the user's Documents folder, +/// rotates the log daily, and compresses old logs with GZip. +/// Compatible with iOS 13.0+ and Swift 6. +public final class NKLogFileManager { + + // MARK: - Singleton + + /// Shared singleton instance of the log manager. + public static let shared = NKLogFileManager() + + /// Configures the shared logger instance. + /// - Parameters: + /// - printLog: Whether to print logs to the console. + /// - minLevel: The minimum log level to be recorded. + /// - retentionDays: Number of days to keep compressed logs. + public static func configure(printLog: Bool = true, + minLevel: LogLevel = .debug, + retentionDays: Int = 30) { + shared.setConfiguration(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) + } + + // MARK: - Configuration + + private let logFileName = "log.txt" + private let logDirectory: URL + private var printLog: Bool + internal var minLevel: LogLevel + private var currentLogDate: String + private var retentionDays: Int + private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) + private let fileManager = FileManager.default + + // MARK: - Initialization + + private init(printLog: Bool = true, minLevel: LogLevel = .debug, retentionDays: Int = 30) { + self.printLog = printLog + self.minLevel = minLevel + self.retentionDays = retentionDays + + let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let logsFolder = documents.appendingPathComponent("Logs", isDirectory: true) + if !FileManager.default.fileExists(atPath: logsFolder.path) { + try? FileManager.default.createDirectory(at: logsFolder, withIntermediateDirectories: true) + } + self.logDirectory = logsFolder + self.currentLogDate = Self.currentDateString() + } + + /// Sets configuration parameters for the logger. + /// - Parameters: + /// - printLog: Whether to print logs to the console. + /// - minLevel: The minimum log level. + /// - retentionDays: Number of days to retain compressed logs. + private func setConfiguration(printLog: Bool, minLevel: LogLevel, retentionDays: Int) { + self.printLog = printLog + self.minLevel = minLevel + self.retentionDays = retentionDays + } + + // MARK: - Public API + + public func compressedLogs() -> [URL] { + guard let files = try? fileManager.contentsOfDirectory(at: logDirectory, includingPropertiesForKeys: nil) else { + return [] + } + return files.filter { $0.pathExtension == "gz" } + } + + public func writeLog(debug message: String) { + guard minLevel <= .debug else { return } + writeLog("[DEBUG] \(message)") + } + + public func writeLog(info message: String) { + guard minLevel <= .info else { return } + writeLog("[INFO] \(message)") + } + + public func writeLog(warning message: String) { + guard minLevel <= .warning else { return } + writeLog("[WARNING] \(message)") + } + + public func writeLog(error message: String) { + guard minLevel <= .error else { return } + writeLog("[ERROR] \(message)") + } + + public func writeLog(tag: String, message: String) { + guard !tag.isEmpty else { return } + writeLog("[\(tag.uppercased())] \(message)") + } + + public func writeLog(_ message: String?) { + guard let message = message else { return } + + let fileTimestamp = Self.stableTimestampString() + let consoleTimestamp = Self.localizedTimestampString() + let fullMessage = "\(fileTimestamp) \(message)\n" + + if printLog { + print(colored("\(consoleTimestamp) \(message)")) + } + + logQueue.async(flags: .barrier) { + self.checkForRotation() + self.appendToLog(fullMessage) + } + } + + private func colored(_ message: String) -> String { + let reset = "\u{001B}[0m" + if message.contains("[ERROR]") { + return "\u{001B}[0;31m" + message + reset + } else if message.contains("[WARNING]") { + return "\u{001B}[0;33m" + message + reset + } else if message.contains("[INFO]") { + return "\u{001B}[0;32m" + message + reset + } else if message.contains("[DEBUG]") { + return "\u{001B}[0;37m" + message + reset + } else { + return "\u{001B}[0;36m" + message + reset + } + } + + // MARK: - Log Rotation + + private func checkForRotation() { + let today = Self.currentDateString() + guard today != currentLogDate else { return } + + rotateLog(for: currentLogDate) + currentLogDate = today + } + + private func rotateLog(for date: String) { + let currentPath = logDirectory.appendingPathComponent(logFileName) + let rotatedPath = logDirectory.appendingPathComponent("log-\(date)") + let compressedPath = rotatedPath.appendingPathExtension("gz") + + do { + if fileManager.fileExists(atPath: currentPath.path) { + try fileManager.moveItem(at: currentPath, to: rotatedPath) + try compressFile(at: rotatedPath, to: compressedPath) + try fileManager.removeItem(at: rotatedPath) + } + + try Data().write(to: currentPath) + cleanupOldLogs() + } catch { + print("Log rotation failed: \(error)") + } + } + + private func cleanupOldLogs() { + let calendar = Calendar.current + let now = Date() + + guard let enumerator = try? fileManager.contentsOfDirectory(at: logDirectory, includingPropertiesForKeys: [.contentModificationDateKey], options: [.skipsHiddenFiles]) else { + return + } + + for fileURL in enumerator { + guard fileURL.pathExtension == "gz" else { continue } + + if let attrs = try? fileURL.resourceValues(forKeys: [.contentModificationDateKey]), + let modDate = attrs.contentModificationDate, + let expiryDate = calendar.date(byAdding: .day, value: -retentionDays, to: now), + modDate < expiryDate { + try? fileManager.removeItem(at: fileURL) + } + } + } + + // MARK: - Log Writing + + private func appendToLog(_ message: String) { + let logPath = logDirectory.appendingPathComponent(logFileName) + + guard let data = message.data(using: .utf8) else { return } + + if fileManager.fileExists(atPath: logPath.path) { + if let handle = FileHandle(forWritingAtPath: logPath.path) { + handle.seekToEndOfFile() + handle.write(data) + handle.closeFile() + } + } else { + try? data.write(to: logPath) + } + } + + // MARK: - Compression + + private func compressFile(at inputURL: URL, to outputURL: URL) throws { + let inputData = try Data(contentsOf: inputURL) + var compressedBuffer = [UInt8](repeating: 0, count: inputData.count) + + let compressedSize = inputData.withUnsafeBytes { srcPtr in + compression_encode_buffer( + &compressedBuffer, + compressedBuffer.count, + srcPtr.baseAddress!.assumingMemoryBound(to: UInt8.self), + inputData.count, + nil, + COMPRESSION_ZLIB + ) + } + + guard compressedSize > 0 else { + throw NSError(domain: "CompressionError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Compression failed"]) + } + + let compressedData = Data(bytes: compressedBuffer, count: compressedSize) + try compressedData.write(to: outputURL) + } + + // MARK: - Date Helpers + + private static func currentDateString() -> String { + let formatter = DateFormatter() + formatter.calendar = Calendar.current + formatter.locale = Locale.current + formatter.timeZone = TimeZone.current + formatter.dateFormat = "yyyy-MM-dd" + return formatter.string(from: Date()) + } + + private static func stableTimestampString() -> String { + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: .gregorian) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone.current + formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + return formatter.string(from: Date()) + } + + private static func localizedTimestampString() -> String { + let formatter = DateFormatter() + formatter.calendar = Calendar.current + formatter.locale = Locale.current + formatter.timeZone = TimeZone.current + formatter.dateStyle = .short + formatter.timeStyle = .medium + return formatter.string(from: Date()) + } +} diff --git a/Sources/NextcloudKit/NKCommon.swift b/Sources/NextcloudKit/NKCommon.swift index 2c305d64..eb2ffa4c 100644 --- a/Sources/NextcloudKit/NKCommon.swift +++ b/Sources/NextcloudKit/NKCommon.swift @@ -128,45 +128,10 @@ public struct NKCommon: Sendable { #endif internal var internalTypeIdentifiers = ThreadSafeArray() - public var filenamePathLog: String = "" - public var levelLog: Int = 0 - public var copyLogToDocumentDirectory: Bool = false - public var printLog: Bool = true - - private var internalFilenameLog: String = "communication.log" - public var filenameLog: String { - get { - return internalFilenameLog - } - set(newVal) { - if !newVal.isEmpty { - internalFilenameLog = newVal - internalFilenameLog = internalPathLog + "/" + internalFilenameLog - } - } - } - - private var internalPathLog: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! - public var pathLog: String { - get { - return internalPathLog - } - set(newVal) { - var tempVal = newVal - if tempVal.last == "/" { - tempVal = String(tempVal.dropLast()) - } - if !tempVal.isEmpty { - internalPathLog = tempVal - filenamePathLog = internalPathLog + "/" + internalFilenameLog - } - } - } - // MARK: - Init init() { - filenamePathLog = internalPathLog + "/" + internalFilenameLog + } // MARK: - Type Identifier @@ -617,91 +582,4 @@ public struct NKCommon: Sendable { } return nil } - - // MARK: - Log - - public func clearFileLog() { - FileManager.default.createFile(atPath: filenamePathLog, contents: nil, attributes: nil) - if copyLogToDocumentDirectory, let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first { - let filenameCopyToDocumentDirectory = path + "/" + filenameLog - FileManager.default.createFile(atPath: filenameCopyToDocumentDirectory, contents: nil, attributes: nil) - - } - } - - /// - /// Write a message with an "[DEBUG] " prefix to the log. - /// - public func writeLog(debug message: String) { - writeLog("[DEBUG] \(message)") - } - - /// - /// Write a message with an "[INFO] " prefix to the log. - /// - public func writeLog(info message: String) { - writeLog("[INFO] \(message)") - } - - /// - /// Write a message with an "[WARNING] " prefix to the log. - /// - public func writeLog(warning message: String) { - writeLog("[WARNING] \(message)") - } - - /// - /// Write a message with an "[ERROR] " prefix to the log. - /// - public func writeLog(error message: String) { - writeLog("[ERROR] \(message)") - } - - /// - /// Write an arbitrary string to the log. - /// - /// Does not write anything, should `text` be `nil`. - /// - public func writeLog(_ text: String?) { - guard let text = text else { - return - } - - guard let date = self.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") else { - return - } - - let textToWrite = "\(date) " + text + "\n" - - if printLog { - print(textToWrite) - } - - if levelLog > 0 { - logQueue.async(flags: .barrier) { - self.writeLogToDisk(filename: self.filenamePathLog, text: textToWrite) - - if self.copyLogToDocumentDirectory, let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first { - let filenameCopyToDocumentDirectory = path + "/" + self.filenameLog - self.writeLogToDisk(filename: filenameCopyToDocumentDirectory, text: textToWrite) - } - } - } - } - - private func writeLogToDisk(filename: String, text: String) { - guard let data = text.data(using: .utf8) else { - return - } - - if !FileManager.default.fileExists(atPath: filename) { - FileManager.default.createFile(atPath: filename, contents: nil, attributes: nil) - } - - if let fileHandle = FileHandle(forWritingAtPath: filename) { - fileHandle.seekToEndOfFile() - fileHandle.write(data) - fileHandle.closeFile() - } - } } diff --git a/Sources/NextcloudKit/NKInterceptor.swift b/Sources/NextcloudKit/NKInterceptor.swift index 394748b3..4665b9b9 100644 --- a/Sources/NextcloudKit/NKInterceptor.swift +++ b/Sources/NextcloudKit/NKInterceptor.swift @@ -13,34 +13,37 @@ final class NKInterceptor: RequestInterceptor, Sendable { } func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { - if let url: String = urlRequest.url?.absoluteString, - self.nkCommonInstance.levelLog > 0 { - debugPrint("[DEBUG] Interceptor request url: " + url) + // Log request URL if needed + if NKLogFileManager.shared.minLevel <= .debug, + let url = urlRequest.url?.absoluteString { + log(debug: "Interceptor request url: \(url)") } + // Skip check if explicitly disabled if let checkInterceptor = urlRequest.value(forHTTPHeaderField: nkCommonInstance.headerCheckInterceptor), checkInterceptor == "false" { return completion(.success(urlRequest)) } + // Check for special error states via group defaults if let account = urlRequest.value(forHTTPHeaderField: nkCommonInstance.headerAccount), let groupDefaults = UserDefaults(suiteName: nkCommonInstance.groupIdentifier) { - /// Unauthorized + if let array = groupDefaults.array(forKey: nkCommonInstance.groupDefaultsUnauthorized) as? [String], array.contains(account) { - self.nkCommonInstance.writeLog("[DEBUG] Unauthorized for account: \(account)") + log(tag: "AUTH", message: "Unauthorized for account: \(account)") let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 401)) return completion(.failure(error)) - /// Unavailable + } else if let array = groupDefaults.array(forKey: nkCommonInstance.groupDefaultsUnavailable) as? [String], array.contains(account) { - self.nkCommonInstance.writeLog("[DEBUG] Unavailable for account: \(account)") + log(tag: "SERVICE", message: "Unavailable for account: \(account)") let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 503)) return completion(.failure(error)) - /// ToS + } else if let array = groupDefaults.array(forKey: nkCommonInstance.groupDefaultsToS) as? [String], array.contains(account) { - self.nkCommonInstance.writeLog("[DEBUG] ToS for account: \(account)") + log(tag: "TOS", message: "Terms of service error for account: \(account)") let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 403)) return completion(.failure(error)) } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index ac650ef4..2696f4e4 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -7,21 +7,27 @@ import Alamofire final class NKMonitor: EventMonitor, Sendable { let nkCommonInstance: NKCommon + let queue = DispatchQueue(label: "com.nextcloudkit.monitor") init(nkCommonInstance: NKCommon) { self.nkCommonInstance = nkCommonInstance } func requestDidResume(_ request: Request) { - if self.nkCommonInstance.levelLog > 0 { - self.nkCommonInstance.writeLog("Network request started: \(request)") - if self.nkCommonInstance.levelLog > 1 { - let allHeaders = request.request.flatMap { $0.allHTTPHeaderFields.map { $0.description } } ?? "None" - let body = request.request.flatMap { $0.httpBody.map { String(decoding: $0, as: UTF8.self) } } ?? "None" - - self.nkCommonInstance.writeLog("Network request headers: \(allHeaders)") - self.nkCommonInstance.writeLog("Network request body: \(body)") - } + let level = NKLogFileManager.shared.minLevel + + // Always log at .info or lower + if level <= .info { + log(info: "Network request started: \(request)") + } + + // If verbose enough, log headers and body + if level <= .debug { + let headers = request.request?.allHTTPHeaderFields?.description ?? "None" + let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" + + log(debug: "Network request headers: \(headers)") + log(debug: "Network request body: \(body)") } } @@ -32,32 +38,32 @@ final class NKMonitor: EventMonitor, Sendable { // Server Error GroupDefaults // if let statusCode = response.response?.statusCode, - let headerCheckInterceptor = request.request?.allHTTPHeaderFields?[self.nkCommonInstance.headerCheckInterceptor], + let headerCheckInterceptor = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerCheckInterceptor], headerCheckInterceptor.lowercased() == "true", - let account = request.request?.allHTTPHeaderFields?[self.nkCommonInstance.headerAccount] as? String { - self.nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode) + let account = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerAccount] { + nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode) } // // LOG // - guard let date = self.nkCommonInstance.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") else { return } - let responseResultString = String("\(response.result)") - let responseDebugDescription = String("\(response.debugDescription)") - let responseAllHeaderFields = String("\(String(describing: response.response?.allHeaderFields))") - - if self.nkCommonInstance.levelLog > 0 { - if self.nkCommonInstance.levelLog == 1 { - if let request = response.request { - let requestString = "\(request)" - self.nkCommonInstance.writeLog("Network response request: " + requestString + ", result: " + responseResultString) - } else { - self.nkCommonInstance.writeLog("Network response result: " + responseResultString) - } + let logLevel = NKLogFileManager.shared.minLevel + + if logLevel <= .info { + let resultStr = String(describing: response.result) + + if let request = response.request { + log(info: "Network response request: \(request), result: \(resultStr)") } else { - self.nkCommonInstance.writeLog("Network response result: \(date) " + responseDebugDescription) - self.nkCommonInstance.writeLog("Network response all headers: \(date) " + responseAllHeaderFields) + log(info: "Network response result: \(resultStr)") } } + + if logLevel <= .debug { + let headers = String(describing: response.response?.allHeaderFields) + let debugDescription = response.debugDescription + log(debug: "Network response debug: \(debugDescription)") + log(debug: "Network response headers: \(headers)") + } } } diff --git a/Sources/NextcloudKit/NextcloudKit+API.swift b/Sources/NextcloudKit/NextcloudKit+API.swift index d23230a5..cf03b12e 100644 --- a/Sources/NextcloudKit/NextcloudKit+API.swift +++ b/Sources/NextcloudKit/NextcloudKit+API.swift @@ -43,9 +43,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -75,9 +72,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -106,9 +100,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -180,9 +171,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -250,10 +238,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -302,9 +286,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -350,9 +331,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -388,9 +366,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -504,9 +479,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -538,9 +510,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -585,9 +554,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -665,9 +631,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -715,9 +678,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -753,9 +713,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -809,9 +766,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -885,9 +839,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -968,9 +919,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -1003,9 +951,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -1047,9 +992,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Assistant.swift b/Sources/NextcloudKit/NextcloudKit+Assistant.swift index 2d795052..cd43104f 100644 --- a/Sources/NextcloudKit/NextcloudKit+Assistant.swift +++ b/Sources/NextcloudKit/NextcloudKit+Assistant.swift @@ -22,9 +22,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -63,9 +60,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -100,9 +94,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -137,9 +128,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -174,9 +162,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift b/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift index 57e20c58..79e38a78 100644 --- a/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift +++ b/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift @@ -23,9 +23,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -68,9 +65,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -105,9 +99,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -142,9 +133,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Comments.swift b/Sources/NextcloudKit/NextcloudKit+Comments.swift index 65149708..6f4074bc 100644 --- a/Sources/NextcloudKit/NextcloudKit+Comments.swift +++ b/Sources/NextcloudKit/NextcloudKit+Comments.swift @@ -36,10 +36,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -86,10 +82,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -133,10 +125,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -166,10 +154,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -211,10 +195,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Dashboard.swift b/Sources/NextcloudKit/NextcloudKit+Dashboard.swift index 516a6bd5..098354e3 100644 --- a/Sources/NextcloudKit/NextcloudKit+Dashboard.swift +++ b/Sources/NextcloudKit/NextcloudKit+Dashboard.swift @@ -23,9 +23,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .success(let jsonData): let json = JSON(jsonData) @@ -62,9 +59,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .success(let jsonData): let json = JSON(jsonData) diff --git a/Sources/NextcloudKit/NextcloudKit+E2EE.swift b/Sources/NextcloudKit/NextcloudKit+E2EE.swift index 434ee018..2a6985bd 100644 --- a/Sources/NextcloudKit/NextcloudKit+E2EE.swift +++ b/Sources/NextcloudKit/NextcloudKit+E2EE.swift @@ -29,9 +29,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -92,9 +89,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -151,9 +145,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -206,9 +197,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -271,9 +259,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -325,9 +310,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -364,9 +346,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -405,9 +384,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -447,9 +423,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -485,9 +458,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -517,9 +487,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+FilesLock.swift b/Sources/NextcloudKit/NextcloudKit+FilesLock.swift index 54d2d493..f80a3290 100644 --- a/Sources/NextcloudKit/NextcloudKit+FilesLock.swift +++ b/Sources/NextcloudKit/NextcloudKit+FilesLock.swift @@ -28,9 +28,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift b/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift index 8641ad10..3620a582 100644 --- a/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift +++ b/Sources/NextcloudKit/NextcloudKit+Groupfolders.swift @@ -23,9 +23,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Hovercard.swift b/Sources/NextcloudKit/NextcloudKit+Hovercard.swift index 2e192c91..8a993854 100644 --- a/Sources/NextcloudKit/NextcloudKit+Hovercard.swift +++ b/Sources/NextcloudKit/NextcloudKit+Hovercard.swift @@ -23,9 +23,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Livephoto.swift b/Sources/NextcloudKit/NextcloudKit+Livephoto.swift index 2eda50d7..6a80bc51 100644 --- a/Sources/NextcloudKit/NextcloudKit+Livephoto.swift +++ b/Sources/NextcloudKit/NextcloudKit+Livephoto.swift @@ -36,9 +36,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift new file mode 100644 index 00000000..e7e7018b --- /dev/null +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +public extension NextcloudKit { + /// Shared logger accessible via NextcloudKit.logger + static var logger: NKLogFileManager { + return NKLogFileManager.shared + } + + /// Configure the shared logger from NextcloudKit + static func configureLogger(printLog: Bool = true, + minLevel: LogLevel = .debug, + retentionDays: Int = 30) { + NKLogFileManager.configure(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) + } +} diff --git a/Sources/NextcloudKit/NextcloudKit+Login.swift b/Sources/NextcloudKit/NextcloudKit+Login.swift index c203689b..64288c8a 100644 --- a/Sources/NextcloudKit/NextcloudKit+Login.swift +++ b/Sources/NextcloudKit/NextcloudKit+Login.swift @@ -36,9 +36,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -84,9 +81,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -149,9 +143,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -186,9 +177,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+NCText.swift b/Sources/NextcloudKit/NextcloudKit+NCText.swift index 4f7f0b2d..a2369971 100644 --- a/Sources/NextcloudKit/NextcloudKit+NCText.swift +++ b/Sources/NextcloudKit/NextcloudKit+NCText.swift @@ -24,9 +24,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -106,9 +103,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -137,9 +131,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -199,9 +190,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+PushNotification.swift b/Sources/NextcloudKit/NextcloudKit+PushNotification.swift index 1052157e..c01e6dae 100644 --- a/Sources/NextcloudKit/NextcloudKit+PushNotification.swift +++ b/Sources/NextcloudKit/NextcloudKit+PushNotification.swift @@ -31,9 +31,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -69,9 +66,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -109,9 +103,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -147,9 +138,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift b/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift index 688c28a6..7f1235d7 100644 --- a/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift +++ b/Sources/NextcloudKit/NextcloudKit+RecommendedFiles.swift @@ -26,9 +26,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .success(let data): if let xmlString = String(data: data, encoding: .utf8) { diff --git a/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift b/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift index 1d7445ba..b71fff46 100644 --- a/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift +++ b/Sources/NextcloudKit/NextcloudKit+Richdocuments.swift @@ -24,9 +24,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -59,9 +56,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -118,9 +112,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -154,9 +145,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Search.swift b/Sources/NextcloudKit/NextcloudKit+Search.swift index 64b8e8df..55fecc86 100644 --- a/Sources/NextcloudKit/NextcloudKit+Search.swift +++ b/Sources/NextcloudKit/NextcloudKit+Search.swift @@ -44,9 +44,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .success(let jsonData): let json = JSON(jsonData) @@ -135,9 +132,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .success(let jsonData): let json = JSON(jsonData) diff --git a/Sources/NextcloudKit/NextcloudKit+Share.swift b/Sources/NextcloudKit/NextcloudKit+Share.swift index 3e821417..9082588b 100644 --- a/Sources/NextcloudKit/NextcloudKit+Share.swift +++ b/Sources/NextcloudKit/NextcloudKit+Share.swift @@ -71,9 +71,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -134,9 +131,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -304,9 +298,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -391,9 +382,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -429,9 +417,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift index 1aaa19ab..fde97bb2 100644 --- a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift +++ b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift @@ -28,10 +28,6 @@ public extension NextcloudKit { .request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -97,10 +93,6 @@ public extension NextcloudKit { .request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) .response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -139,10 +131,6 @@ public extension NextcloudKit { .request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) .response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } - switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift b/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift index 862e5c00..9799ce98 100644 --- a/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift +++ b/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift @@ -23,9 +23,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .success(let jsonData): let tos = NKTermsOfService() @@ -74,9 +71,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+UserStatus.swift b/Sources/NextcloudKit/NextcloudKit+UserStatus.swift index 8dce2239..de772e5a 100644 --- a/Sources/NextcloudKit/NextcloudKit+UserStatus.swift +++ b/Sources/NextcloudKit/NextcloudKit+UserStatus.swift @@ -26,9 +26,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -91,9 +88,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -133,9 +127,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -180,9 +171,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -215,9 +203,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -250,9 +235,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -307,9 +289,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index 86dea614..faf1dc61 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -30,9 +30,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -84,9 +81,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -138,9 +132,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -195,9 +186,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -264,9 +252,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -438,9 +423,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -489,9 +471,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.response(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -546,9 +525,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -612,9 +588,6 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - if self.nkCommonInstance.levelLog > 0 { - debugPrint(response) - } switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit.swift b/Sources/NextcloudKit/NextcloudKit.swift index 8d843023..eb339707 100644 --- a/Sources/NextcloudKit/NextcloudKit.swift +++ b/Sources/NextcloudKit/NextcloudKit.swift @@ -22,6 +22,10 @@ open class NextcloudKit { #endif public var nkCommonInstance = NKCommon() + internal func log(debug message: String) { + NKLogFileManager.shared.writeLog(debug: message) + } + internal lazy var unauthorizedSession: Alamofire.Session = { let configuration = URLSessionConfiguration.af.default configuration.requestCachePolicy = .reloadIgnoringLocalCacheData @@ -73,14 +77,6 @@ open class NextcloudKit { } } - public func setupLog(pathLog: String, - levelLog: Int, - copyLogToDocumentDirectory: Bool) { - self.nkCommonInstance.pathLog = pathLog - self.nkCommonInstance.levelLog = levelLog - self.nkCommonInstance.copyLogToDocumentDirectory = copyLogToDocumentDirectory - } - public func appendSession(account: String, urlBase: String, user: String, diff --git a/Sources/NextcloudKit/NextcloudKitBackground.swift b/Sources/NextcloudKit/NextcloudKitBackground.swift index 7a33ec87..dbcefc3c 100644 --- a/Sources/NextcloudKit/NextcloudKitBackground.swift +++ b/Sources/NextcloudKit/NextcloudKitBackground.swift @@ -59,7 +59,6 @@ public final class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDel let task = nkSession.sessionDownloadBackground.downloadTask(with: request) task.taskDescription = taskDescription task.resume() - self.nkCommonInstance.writeLog("Network start download file: \(serverUrlFileName)") return (task, .success) } @@ -135,7 +134,6 @@ public final class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDel let task = uploadSession?.uploadTask(with: request, fromFile: URL(fileURLWithPath: fileNameLocalPath)) task?.taskDescription = taskDescription task?.resume() - self.nkCommonInstance.writeLog("Network start upload file: \(serverUrlFileName)") return (task, .success) } @@ -215,23 +213,13 @@ public final class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDel } else if task is URLSessionUploadTask { self.nkCommonInstance.delegate?.uploadComplete(fileName: fileName, serverUrl: serverUrl, ocId: ocId, etag: etag, date: date, size: task.countOfBytesExpectedToSend, task: task, error: nkError) } - - if nkError.errorCode == 0 { - self.nkCommonInstance.writeLog("Network completed file: \(serverUrl)/\(fileName)") - } else { - self.nkCommonInstance.writeLog("Network completed file: \(serverUrl)/\(fileName) with error code \(nkError.errorCode) and error description " + nkError.errorDescription) - } } public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if self.nkCommonInstance.delegate == nil { - self.nkCommonInstance.writeLog("[WARNING] URLAuthenticationChallenge, no delegate found, perform with default handling") completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) } else { self.nkCommonInstance.delegate?.authenticationChallenge(session, didReceive: challenge, completionHandler: { authChallengeDisposition, credential in - if self.nkCommonInstance.levelLog > 1 { - self.nkCommonInstance.writeLog("[INFO AUTH] Challenge Disposition: \(authChallengeDisposition.rawValue)") - } completionHandler(authChallengeDisposition, credential) }) } diff --git a/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift b/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift index 9d9c65ce..789d00a1 100644 --- a/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift +++ b/Sources/NextcloudKit/NextcloudKitSessionDelegate.swift @@ -25,13 +25,9 @@ final class NextcloudKitSessionDelegate: SessionDelegate { if let nkCommon = self.nkCommonInstance, let delegate = nkCommon.delegate { delegate.authenticationChallenge(session, didReceive: challenge) { authChallengeDisposition, credential in - if nkCommon.levelLog > 1 { - nkCommon.writeLog("[INFO AUTH] Challenge Disposition: \(authChallengeDisposition.rawValue)") - } completionHandler(authChallengeDisposition, credential) } } else { - self.nkCommonInstance?.writeLog("[WARNING] URLAuthenticationChallenge, no delegate found, perform with default handling") completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil) } } From a0c6f67142baa4592ecf252b8f159f7e6de0825d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 10:44:22 +0200 Subject: [PATCH 02/54] cleaning Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 31 +++++++++----- Sources/NextcloudKit/NKInterceptor.swift | 2 +- Sources/NextcloudKit/NKMonitor.swift | 40 +++++++++---------- .../NextcloudKit/NextcloudKit+Logging.swift | 2 +- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index a064b717..789aabf5 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -2,15 +2,24 @@ // SPDX-FileCopyrightText: 2025 Marino Faggiana // SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + import Foundation import Compression /// Defines the severity level of a log message. +/// Defines the level of log verbosity. public enum LogLevel: Int, Comparable { - case debug = 0 - case info = 1 - case warning = 2 - case error = 3 + /// Logging is disabled. + case off = 0 + + /// Logs essential events such as requests and errors. + case normal = 1 + + /// Logs detailed debug information including headers and bodies. + case verbose = 2 public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool { return lhs.rawValue < rhs.rawValue @@ -33,7 +42,7 @@ public final class NKLogFileManager { /// - minLevel: The minimum log level to be recorded. /// - retentionDays: Number of days to keep compressed logs. public static func configure(printLog: Bool = true, - minLevel: LogLevel = .debug, + minLevel: LogLevel = .normal, retentionDays: Int = 30) { shared.setConfiguration(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) } @@ -51,7 +60,7 @@ public final class NKLogFileManager { // MARK: - Initialization - private init(printLog: Bool = true, minLevel: LogLevel = .debug, retentionDays: Int = 30) { + private init(printLog: Bool = true, minLevel: LogLevel = .normal, retentionDays: Int = 30) { self.printLog = printLog self.minLevel = minLevel self.retentionDays = retentionDays @@ -86,31 +95,33 @@ public final class NKLogFileManager { } public func writeLog(debug message: String) { - guard minLevel <= .debug else { return } + guard minLevel == .verbose else { return } writeLog("[DEBUG] \(message)") } public func writeLog(info message: String) { - guard minLevel <= .info else { return } + guard minLevel >= .normal else { return } writeLog("[INFO] \(message)") } public func writeLog(warning message: String) { - guard minLevel <= .warning else { return } + guard minLevel >= .normal else { return } writeLog("[WARNING] \(message)") } public func writeLog(error message: String) { - guard minLevel <= .error else { return } + guard minLevel >= .normal else { return } writeLog("[ERROR] \(message)") } public func writeLog(tag: String, message: String) { guard !tag.isEmpty else { return } + guard minLevel >= .normal else { return } writeLog("[\(tag.uppercased())] \(message)") } public func writeLog(_ message: String?) { + guard minLevel != .off else { return } guard let message = message else { return } let fileTimestamp = Self.stableTimestampString() diff --git a/Sources/NextcloudKit/NKInterceptor.swift b/Sources/NextcloudKit/NKInterceptor.swift index 4665b9b9..e401c825 100644 --- a/Sources/NextcloudKit/NKInterceptor.swift +++ b/Sources/NextcloudKit/NKInterceptor.swift @@ -14,7 +14,7 @@ final class NKInterceptor: RequestInterceptor, Sendable { func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { // Log request URL if needed - if NKLogFileManager.shared.minLevel <= .debug, + if NKLogFileManager.shared.minLevel == .verbose, let url = urlRequest.url?.absoluteString { log(debug: "Interceptor request url: \(url)") } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 2696f4e4..ba8498bf 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -16,13 +16,13 @@ final class NKMonitor: EventMonitor, Sendable { func requestDidResume(_ request: Request) { let level = NKLogFileManager.shared.minLevel - // Always log at .info or lower - if level <= .info { + // Log always if enabled at normal level + if level >= .normal { log(info: "Network request started: \(request)") } - // If verbose enough, log headers and body - if level <= .debug { + // Log headers and body only in verbose mode + if level == .verbose { let headers = request.request?.allHTTPHeaderFields?.description ?? "None" let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" @@ -45,25 +45,25 @@ final class NKMonitor: EventMonitor, Sendable { } // - // LOG - // - let logLevel = NKLogFileManager.shared.minLevel + // LOG + // + let logLevel = NKLogFileManager.shared.minLevel - if logLevel <= .info { - let resultStr = String(describing: response.result) + if logLevel >= .normal { + let resultStr = String(describing: response.result) - if let request = response.request { - log(info: "Network response request: \(request), result: \(resultStr)") - } else { - log(info: "Network response result: \(resultStr)") + if let request = response.request { + log(info: "Network response request: \(request), result: \(resultStr)") + } else { + log(info: "Network response result: \(resultStr)") + } } - } - if logLevel <= .debug { - let headers = String(describing: response.response?.allHeaderFields) - let debugDescription = response.debugDescription - log(debug: "Network response debug: \(debugDescription)") - log(debug: "Network response headers: \(headers)") - } + if logLevel == .verbose { + let headers = String(describing: response.response?.allHeaderFields) + let debugDescription = response.debugDescription + log(debug: "Network response debug: \(debugDescription)") + log(debug: "Network response headers: \(headers)") + } } } diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index e7e7018b..6ccc171b 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -10,7 +10,7 @@ public extension NextcloudKit { /// Configure the shared logger from NextcloudKit static func configureLogger(printLog: Bool = true, - minLevel: LogLevel = .debug, + minLevel: LogLevel = .normal, retentionDays: Int = 30) { NKLogFileManager.configure(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) } From fa490ad5fb29a3eddae13af11b891ee2ed84b4c6 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 11:01:13 +0200 Subject: [PATCH 03/54] improved Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 23 +++++--- Sources/NextcloudKit/NKInterceptor.swift | 6 ++- Sources/NextcloudKit/NKMonitor.swift | 52 +++++++++---------- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 789aabf5..3899e649 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -15,14 +15,17 @@ public enum LogLevel: Int, Comparable { /// Logging is disabled. case off = 0 - /// Logs essential events such as requests and errors. - case normal = 1 + /// Logs basic request lifecycle for developers (request started, response result). + case trace = 1 - /// Logs detailed debug information including headers and bodies. - case verbose = 2 + /// Logs important info such as result content, errors. + case normal = 2 + + /// Logs detailed debug info like headers and bodies. + case verbose = 3 public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool { - return lhs.rawValue < rhs.rawValue + lhs.rawValue < rhs.rawValue } } @@ -114,9 +117,15 @@ public final class NKLogFileManager { writeLog("[ERROR] \(message)") } - public func writeLog(tag: String, message: String) { + /// Writes a tagged log message with a specific log level. + /// - Parameters: + /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). + /// - message: The log message content. + /// - level: The minimum level required for this message to be written. + public func writeLog(tag: String, message: String, level: LogLevel = .normal) { guard !tag.isEmpty else { return } - guard minLevel >= .normal else { return } + guard minLevel >= level else { return } + writeLog("[\(tag.uppercased())] \(message)") } diff --git a/Sources/NextcloudKit/NKInterceptor.swift b/Sources/NextcloudKit/NKInterceptor.swift index e401c825..b01df8ce 100644 --- a/Sources/NextcloudKit/NKInterceptor.swift +++ b/Sources/NextcloudKit/NKInterceptor.swift @@ -13,8 +13,10 @@ final class NKInterceptor: RequestInterceptor, Sendable { } func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { - // Log request URL if needed - if NKLogFileManager.shared.minLevel == .verbose, + let logLevel = NKLogFileManager.shared.minLevel + + // Log request URL in verbose mode + if logLevel == .verbose, let url = urlRequest.url?.absoluteString { log(debug: "Interceptor request url: \(url)") } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index ba8498bf..4ca2d438 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -16,27 +16,22 @@ final class NKMonitor: EventMonitor, Sendable { func requestDidResume(_ request: Request) { let level = NKLogFileManager.shared.minLevel - // Log always if enabled at normal level - if level >= .normal { - log(info: "Network request started: \(request)") + if level >= .trace { + log(info: "Request started: \(request)") } - // Log headers and body only in verbose mode if level == .verbose { let headers = request.request?.allHTTPHeaderFields?.description ?? "None" let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" - log(debug: "Network request headers: \(headers)") - log(debug: "Network request body: \(body)") + log(debug: "Headers: \(headers)") + log(debug: "Body: \(body)") } } func request(_ request: DataRequest, didParseResponse response: AFDataResponse) { nkCommonInstance.delegate?.request(request, didParseResponse: response) - // - // Server Error GroupDefaults - // if let statusCode = response.response?.statusCode, let headerCheckInterceptor = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerCheckInterceptor], headerCheckInterceptor.lowercased() == "true", @@ -44,26 +39,31 @@ final class NKMonitor: EventMonitor, Sendable { nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode) } - // - // LOG - // - let logLevel = NKLogFileManager.shared.minLevel - - if logLevel >= .normal { - let resultStr = String(describing: response.result) + let level = NKLogFileManager.shared.minLevel - if let request = response.request { - log(info: "Network response request: \(request), result: \(resultStr)") - } else { - log(info: "Network response result: \(resultStr)") - } + if level >= .trace { + if case let .failure(error) = response.result { + log(info: "Response failed: \(error.localizedDescription)") + } else { + log(info: "Response succeeded.") } + } + + if level >= .normal { + let resultStr = String(describing: response.result) - if logLevel == .verbose { - let headers = String(describing: response.response?.allHeaderFields) - let debugDescription = response.debugDescription - log(debug: "Network response debug: \(debugDescription)") - log(debug: "Network response headers: \(headers)") + if let request = response.request { + log(info: "Full response from \(request): \(resultStr)") + } else { + log(info: "Response result: \(resultStr)") } + } + + if level == .verbose { + let headers = String(describing: response.response?.allHeaderFields) + let debugDescription = response.debugDescription + log(debug: "Debug info: \(debugDescription)") + log(debug: "Headers: \(headers)") + } } } From d265f25f83a23f26933847e8941d8543803f1f1b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 11:12:00 +0200 Subject: [PATCH 04/54] improvements Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 35 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index d7c0f18d..5a8674c8 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -1,29 +1,38 @@ -// -// NKLog.swift -// NextcloudKit -// -// Created by Marino Faggiana on 07/06/25. -// +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later import Foundation -/// Internal log helpers for use inside the NextcloudKit module. -internal func log(debug message: String) { +/// Public logging helpers for apps using the NextcloudKit library. +/// These functions internally use `NKLogFileManager.shared`. + +@inlinable +public func log(debug message: String) { NKLogFileManager.shared.writeLog(debug: message) } -internal func log(info message: String) { +@inlinable +public func log(info message: String) { NKLogFileManager.shared.writeLog(info: message) } -internal func log(warning message: String) { +@inlinable +public func log(warning message: String) { NKLogFileManager.shared.writeLog(warning: message) } -internal func log(error message: String) { +@inlinable +public func log(error message: String) { NKLogFileManager.shared.writeLog(error: message) } -internal func log(tag: String, message: String) { - NKLogFileManager.shared.writeLog(tag: tag, message: message) +/// Logs a custom tagged message at the specified level. +/// - Parameters: +/// - tag: A custom uppercase tag, e.g. \"UPLOAD\", \"SYNC\", \"AUTH\". +/// - message: The message to log. +/// - level: The minimum level required for the message to be recorded. +@inlinable +public func log(tag: String, message: String, level: LogLevel = .normal) { + NKLogFileManager.shared.writeLog(tag: tag, message: message, level: level) } From 534fd5f6ae34fbe9849e2fec2f615109c10617d8 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 11:19:28 +0200 Subject: [PATCH 05/54] rename Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 10 +++++----- Sources/NextcloudKit/NKInterceptor.swift | 8 ++++---- Sources/NextcloudKit/NKMonitor.swift | 18 +++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 5a8674c8..a39ebb92 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -8,22 +8,22 @@ import Foundation /// These functions internally use `NKLogFileManager.shared`. @inlinable -public func log(debug message: String) { +public func nkLog(debug message: String) { NKLogFileManager.shared.writeLog(debug: message) } @inlinable -public func log(info message: String) { +public func nkLog(info message: String) { NKLogFileManager.shared.writeLog(info: message) } @inlinable -public func log(warning message: String) { +public func nkLog(warning message: String) { NKLogFileManager.shared.writeLog(warning: message) } @inlinable -public func log(error message: String) { +public func nkLog(error message: String) { NKLogFileManager.shared.writeLog(error: message) } @@ -33,6 +33,6 @@ public func log(error message: String) { /// - message: The message to log. /// - level: The minimum level required for the message to be recorded. @inlinable -public func log(tag: String, message: String, level: LogLevel = .normal) { +public func nkLog(tag: String, message: String, level: LogLevel = .normal) { NKLogFileManager.shared.writeLog(tag: tag, message: message, level: level) } diff --git a/Sources/NextcloudKit/NKInterceptor.swift b/Sources/NextcloudKit/NKInterceptor.swift index b01df8ce..b164d144 100644 --- a/Sources/NextcloudKit/NKInterceptor.swift +++ b/Sources/NextcloudKit/NKInterceptor.swift @@ -18,7 +18,7 @@ final class NKInterceptor: RequestInterceptor, Sendable { // Log request URL in verbose mode if logLevel == .verbose, let url = urlRequest.url?.absoluteString { - log(debug: "Interceptor request url: \(url)") + nkLog(debug: "Interceptor request url: \(url)") } // Skip check if explicitly disabled @@ -33,19 +33,19 @@ final class NKInterceptor: RequestInterceptor, Sendable { if let array = groupDefaults.array(forKey: nkCommonInstance.groupDefaultsUnauthorized) as? [String], array.contains(account) { - log(tag: "AUTH", message: "Unauthorized for account: \(account)") + nkLog(tag: "AUTH", message: "Unauthorized for account: \(account)") let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 401)) return completion(.failure(error)) } else if let array = groupDefaults.array(forKey: nkCommonInstance.groupDefaultsUnavailable) as? [String], array.contains(account) { - log(tag: "SERVICE", message: "Unavailable for account: \(account)") + nkLog(tag: "SERVICE", message: "Unavailable for account: \(account)") let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 503)) return completion(.failure(error)) } else if let array = groupDefaults.array(forKey: nkCommonInstance.groupDefaultsToS) as? [String], array.contains(account) { - log(tag: "TOS", message: "Terms of service error for account: \(account)") + nkLog(tag: "TOS", message: "Terms of service error for account: \(account)") let error = AFError.responseValidationFailed(reason: .unacceptableStatusCode(code: 403)) return completion(.failure(error)) } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 4ca2d438..f464c3fa 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -17,15 +17,15 @@ final class NKMonitor: EventMonitor, Sendable { let level = NKLogFileManager.shared.minLevel if level >= .trace { - log(info: "Request started: \(request)") + nkLog(info: "Request started: \(request)") } if level == .verbose { let headers = request.request?.allHTTPHeaderFields?.description ?? "None" let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" - log(debug: "Headers: \(headers)") - log(debug: "Body: \(body)") + nkLog(debug: "Headers: \(headers)") + nkLog(debug: "Body: \(body)") } } @@ -43,9 +43,9 @@ final class NKMonitor: EventMonitor, Sendable { if level >= .trace { if case let .failure(error) = response.result { - log(info: "Response failed: \(error.localizedDescription)") + nkLog(info: "Response failed: \(error.localizedDescription)") } else { - log(info: "Response succeeded.") + nkLog(info: "Response succeeded.") } } @@ -53,17 +53,17 @@ final class NKMonitor: EventMonitor, Sendable { let resultStr = String(describing: response.result) if let request = response.request { - log(info: "Full response from \(request): \(resultStr)") + nkLog(info: "Full response from \(request): \(resultStr)") } else { - log(info: "Response result: \(resultStr)") + nkLog(info: "Response result: \(resultStr)") } } if level == .verbose { let headers = String(describing: response.response?.allHeaderFields) let debugDescription = response.debugDescription - log(debug: "Debug info: \(debugDescription)") - log(debug: "Headers: \(headers)") + nkLog(debug: "Debug info: \(debugDescription)") + nkLog(debug: "Headers: \(headers)") } } } From 4a0b997195fe01b5e8b2a8b17ac9b537e7e23441 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 11:47:26 +0200 Subject: [PATCH 06/54] code Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 3899e649..86fc085a 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -55,7 +55,7 @@ public final class NKLogFileManager { private let logFileName = "log.txt" private let logDirectory: URL private var printLog: Bool - internal var minLevel: LogLevel + public var minLevel: LogLevel private var currentLogDate: String private var retentionDays: Int private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) From aeb277d20d5a1944ab7e7df8aea04f9a7f5f54a7 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 12:20:20 +0200 Subject: [PATCH 07/54] code Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 86fc085a..7cbe543b 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -50,6 +50,11 @@ public final class NKLogFileManager { shared.setConfiguration(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) } + /// Returns the file URL of the currently active log file. + public func currentLogFileURL() -> URL { + return logDirectory.appendingPathComponent(logFileName) + } + // MARK: - Configuration private let logFileName = "log.txt" From 095e5173e7f091d411620b5440da5a7caa81eeff Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 13:00:28 +0200 Subject: [PATCH 08/54] new color Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 7cbe543b..2f2b656e 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -42,12 +42,15 @@ public final class NKLogFileManager { /// Configures the shared logger instance. /// - Parameters: /// - printLog: Whether to print logs to the console. + /// - printColor: Whether to print logs to the console with the emojiColored /// - minLevel: The minimum log level to be recorded. /// - retentionDays: Number of days to keep compressed logs. + public static func configure(printLog: Bool = true, + printColor: Bool = true, minLevel: LogLevel = .normal, retentionDays: Int = 30) { - shared.setConfiguration(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) + shared.setConfiguration(printLog: printLog, printColor: printColor, minLevel: minLevel, retentionDays: retentionDays) } /// Returns the file URL of the currently active log file. @@ -60,6 +63,7 @@ public final class NKLogFileManager { private let logFileName = "log.txt" private let logDirectory: URL private var printLog: Bool + private var printColor: Bool = true public var minLevel: LogLevel private var currentLogDate: String private var retentionDays: Int @@ -85,10 +89,13 @@ public final class NKLogFileManager { /// Sets configuration parameters for the logger. /// - Parameters: /// - printLog: Whether to print logs to the console. + /// - printColor: Whether to print logs to the console with the emojiColored /// - minLevel: The minimum log level. /// - retentionDays: Number of days to retain compressed logs. - private func setConfiguration(printLog: Bool, minLevel: LogLevel, retentionDays: Int) { + /// + private func setConfiguration(printLog: Bool, printColor: Bool, minLevel: LogLevel, retentionDays: Int) { self.printLog = printLog + self.printColor = printColor self.minLevel = minLevel self.retentionDays = retentionDays } @@ -143,7 +150,10 @@ public final class NKLogFileManager { let fullMessage = "\(fileTimestamp) \(message)\n" if printLog { - print(colored("\(consoleTimestamp) \(message)")) + let consoleLine = printColor + ? emojiColored("\(consoleTimestamp) \(message)") + : "\(consoleTimestamp) \(message)" + print(consoleLine) } logQueue.async(flags: .barrier) { @@ -152,18 +162,17 @@ public final class NKLogFileManager { } } - private func colored(_ message: String) -> String { - let reset = "\u{001B}[0m" + private func emojiColored(_ message: String) -> String { if message.contains("[ERROR]") { - return "\u{001B}[0;31m" + message + reset + return "🔴 " + message } else if message.contains("[WARNING]") { - return "\u{001B}[0;33m" + message + reset + return "🟡 " + message } else if message.contains("[INFO]") { - return "\u{001B}[0;32m" + message + reset + return "đŸŸĸ " + message } else if message.contains("[DEBUG]") { - return "\u{001B}[0;37m" + message + reset + return "âšĒī¸ " + message } else { - return "\u{001B}[0;36m" + message + reset + return "🔷 " + message } } From 0c09abc3d31264cf3446e77b37c815de991ee984 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 13:02:52 +0200 Subject: [PATCH 09/54] code Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NextcloudKit+Logging.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index 6ccc171b..3895ce2f 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -10,8 +10,12 @@ public extension NextcloudKit { /// Configure the shared logger from NextcloudKit static func configureLogger(printLog: Bool = true, + printColor: Bool = true, minLevel: LogLevel = .normal, retentionDays: Int = 30) { - NKLogFileManager.configure(printLog: printLog, minLevel: minLevel, retentionDays: retentionDays) + NKLogFileManager.configure(printLog: printLog, + printColor: printColor, + minLevel: minLevel, + retentionDays: retentionDays) } } From 3d8047c57c1526952d4334ead675abf8cc9c828e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 18:14:11 +0200 Subject: [PATCH 10/54] NKLogLevel Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 2 +- Sources/NextcloudKit/Log/NKLogFileManager.swift | 14 +++++++------- .../NextcloudKit/NextcloudKit+AssistantV2.swift | 2 +- Sources/NextcloudKit/NextcloudKit+Logging.swift | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index a39ebb92..09df06f6 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -33,6 +33,6 @@ public func nkLog(error message: String) { /// - message: The message to log. /// - level: The minimum level required for the message to be recorded. @inlinable -public func nkLog(tag: String, message: String, level: LogLevel = .normal) { +public func nkLog(tag: String, message: String, level: NKLogLevel = .normal) { NKLogFileManager.shared.writeLog(tag: tag, message: message, level: level) } diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 2f2b656e..754d436f 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -11,7 +11,7 @@ import Compression /// Defines the severity level of a log message. /// Defines the level of log verbosity. -public enum LogLevel: Int, Comparable { +public enum NKLogLevel: Int, Comparable { /// Logging is disabled. case off = 0 @@ -24,7 +24,7 @@ public enum LogLevel: Int, Comparable { /// Logs detailed debug info like headers and bodies. case verbose = 3 - public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool { + public static func < (lhs: NKLogLevel, rhs: NKLogLevel) -> Bool { lhs.rawValue < rhs.rawValue } } @@ -48,7 +48,7 @@ public final class NKLogFileManager { public static func configure(printLog: Bool = true, printColor: Bool = true, - minLevel: LogLevel = .normal, + minLevel: NKLogLevel = .normal, retentionDays: Int = 30) { shared.setConfiguration(printLog: printLog, printColor: printColor, minLevel: minLevel, retentionDays: retentionDays) } @@ -64,7 +64,7 @@ public final class NKLogFileManager { private let logDirectory: URL private var printLog: Bool private var printColor: Bool = true - public var minLevel: LogLevel + public var minLevel: NKLogLevel private var currentLogDate: String private var retentionDays: Int private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) @@ -72,7 +72,7 @@ public final class NKLogFileManager { // MARK: - Initialization - private init(printLog: Bool = true, minLevel: LogLevel = .normal, retentionDays: Int = 30) { + private init(printLog: Bool = true, minLevel: NKLogLevel = .normal, retentionDays: Int = 30) { self.printLog = printLog self.minLevel = minLevel self.retentionDays = retentionDays @@ -93,7 +93,7 @@ public final class NKLogFileManager { /// - minLevel: The minimum log level. /// - retentionDays: Number of days to retain compressed logs. /// - private func setConfiguration(printLog: Bool, printColor: Bool, minLevel: LogLevel, retentionDays: Int) { + private func setConfiguration(printLog: Bool, printColor: Bool, minLevel: NKLogLevel, retentionDays: Int) { self.printLog = printLog self.printColor = printColor self.minLevel = minLevel @@ -134,7 +134,7 @@ public final class NKLogFileManager { /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). /// - message: The log message content. /// - level: The minimum level required for this message to be written. - public func writeLog(tag: String, message: String, level: LogLevel = .normal) { + public func writeLog(tag: String, message: String, level: NKLogLevel = .normal) { guard !tag.isEmpty else { return } guard minLevel >= level else { return } diff --git a/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift b/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift index 79e38a78..ec68ca44 100644 --- a/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift +++ b/Sources/NextcloudKit/NextcloudKit+AssistantV2.swift @@ -34,7 +34,7 @@ public extension NextcloudKit { if 200..<300 ~= statusCode { let dict = TaskTypes.deserialize(from: data) let result = dict?.types.map({$0}) - var filteredResult = result? + let filteredResult = result? .filter({ $0.inputShape?.input?.type == supportedTaskType && $0.outputShape?.output?.type == supportedTaskType }) .sorted(by: {$0.id! < $1.id!}) options.queue.async { completion(account, filteredResult, response, .success) } diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index 3895ce2f..1196d243 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -11,7 +11,7 @@ public extension NextcloudKit { /// Configure the shared logger from NextcloudKit static func configureLogger(printLog: Bool = true, printColor: Bool = true, - minLevel: LogLevel = .normal, + minLevel: NKLogLevel = .normal, retentionDays: Int = 30) { NKLogFileManager.configure(printLog: printLog, printColor: printColor, From 0758e2c235004b8c3351852baa52b03c79991cd0 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 18:20:43 +0200 Subject: [PATCH 11/54] fix Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 754d436f..3642532a 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -11,7 +11,7 @@ import Compression /// Defines the severity level of a log message. /// Defines the level of log verbosity. -public enum NKLogLevel: Int, Comparable { +public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { /// Logging is disabled. case off = 0 @@ -24,6 +24,20 @@ public enum NKLogLevel: Int, Comparable { /// Logs detailed debug info like headers and bodies. case verbose = 3 + // Needed for Picker + public var id: Int { rawValue } + + // For Picker display + public var displayText: String { + switch self { + case .off: return NSLocalizedString("_disabled_", comment: "") + case .trace: return NSLocalizedString("_trace_", comment: "") + case .normal: return NSLocalizedString("_normal_", comment: "") + case .verbose: return NSLocalizedString("_verbose_", comment: "") + } + } + + // For Comparable public static func < (lhs: NKLogLevel, rhs: NKLogLevel) -> Bool { lhs.rawValue < rhs.rawValue } From 47e4e595e8cf6bd12c0dfcd2ef47cecd6293a63c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 18:29:48 +0200 Subject: [PATCH 12/54] cod Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 3642532a..667883ab 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -124,22 +124,18 @@ public final class NKLogFileManager { } public func writeLog(debug message: String) { - guard minLevel == .verbose else { return } writeLog("[DEBUG] \(message)") } public func writeLog(info message: String) { - guard minLevel >= .normal else { return } writeLog("[INFO] \(message)") } public func writeLog(warning message: String) { - guard minLevel >= .normal else { return } writeLog("[WARNING] \(message)") } public func writeLog(error message: String) { - guard minLevel >= .normal else { return } writeLog("[ERROR] \(message)") } @@ -150,7 +146,6 @@ public final class NKLogFileManager { /// - level: The minimum level required for this message to be written. public func writeLog(tag: String, message: String, level: NKLogLevel = .normal) { guard !tag.isEmpty else { return } - guard minLevel >= level else { return } writeLog("[\(tag.uppercased())] \(message)") } From e78cd704a60903bf1cb6c875eb5a12cb9cd71fa2 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 18:30:45 +0200 Subject: [PATCH 13/54] clean Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 4 ++-- Sources/NextcloudKit/Log/NKLogFileManager.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 09df06f6..24506073 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -33,6 +33,6 @@ public func nkLog(error message: String) { /// - message: The message to log. /// - level: The minimum level required for the message to be recorded. @inlinable -public func nkLog(tag: String, message: String, level: NKLogLevel = .normal) { - NKLogFileManager.shared.writeLog(tag: tag, message: message, level: level) +public func nkLog(tag: String, message: String) { + NKLogFileManager.shared.writeLog(tag: tag, message: message) } diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 667883ab..415159c0 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -144,7 +144,7 @@ public final class NKLogFileManager { /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). /// - message: The log message content. /// - level: The minimum level required for this message to be written. - public func writeLog(tag: String, message: String, level: NKLogLevel = .normal) { + public func writeLog(tag: String, message: String) { guard !tag.isEmpty else { return } writeLog("[\(tag.uppercased())] \(message)") From 94f006871937a854d1281b81e7a19d0c8c93f393 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 18:46:21 +0200 Subject: [PATCH 14/54] cod Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 16 +++--- Sources/NextcloudKit/NKInterceptor.swift | 4 +- Sources/NextcloudKit/NKMonitor.swift | 49 +++++++++---------- .../NextcloudKit/NextcloudKit+Logging.swift | 4 +- 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 415159c0..b736810f 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -62,9 +62,9 @@ public final class NKLogFileManager { public static func configure(printLog: Bool = true, printColor: Bool = true, - minLevel: NKLogLevel = .normal, + logLevel: NKLogLevel = .normal, retentionDays: Int = 30) { - shared.setConfiguration(printLog: printLog, printColor: printColor, minLevel: minLevel, retentionDays: retentionDays) + shared.setConfiguration(printLog: printLog, printColor: printColor, logLevel: logLevel, retentionDays: retentionDays) } /// Returns the file URL of the currently active log file. @@ -78,7 +78,7 @@ public final class NKLogFileManager { private let logDirectory: URL private var printLog: Bool private var printColor: Bool = true - public var minLevel: NKLogLevel + public var logLevel: NKLogLevel private var currentLogDate: String private var retentionDays: Int private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) @@ -86,9 +86,9 @@ public final class NKLogFileManager { // MARK: - Initialization - private init(printLog: Bool = true, minLevel: NKLogLevel = .normal, retentionDays: Int = 30) { + private init(printLog: Bool = true, logLevel: NKLogLevel = .normal, retentionDays: Int = 30) { self.printLog = printLog - self.minLevel = minLevel + self.logLevel = logLevel self.retentionDays = retentionDays let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! @@ -107,10 +107,10 @@ public final class NKLogFileManager { /// - minLevel: The minimum log level. /// - retentionDays: Number of days to retain compressed logs. /// - private func setConfiguration(printLog: Bool, printColor: Bool, minLevel: NKLogLevel, retentionDays: Int) { + private func setConfiguration(printLog: Bool, printColor: Bool, logLevel: NKLogLevel, retentionDays: Int) { self.printLog = printLog self.printColor = printColor - self.minLevel = minLevel + self.logLevel = logLevel self.retentionDays = retentionDays } @@ -151,7 +151,7 @@ public final class NKLogFileManager { } public func writeLog(_ message: String?) { - guard minLevel != .off else { return } + guard logLevel != .off else { return } guard let message = message else { return } let fileTimestamp = Self.stableTimestampString() diff --git a/Sources/NextcloudKit/NKInterceptor.swift b/Sources/NextcloudKit/NKInterceptor.swift index b164d144..232a0945 100644 --- a/Sources/NextcloudKit/NKInterceptor.swift +++ b/Sources/NextcloudKit/NKInterceptor.swift @@ -13,10 +13,8 @@ final class NKInterceptor: RequestInterceptor, Sendable { } func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { - let logLevel = NKLogFileManager.shared.minLevel - // Log request URL in verbose mode - if logLevel == .verbose, + if NKLogFileManager.shared.logLevel == .verbose, let url = urlRequest.url?.absoluteString { nkLog(debug: "Interceptor request url: \(url)") } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index f464c3fa..10a51df3 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -14,18 +14,16 @@ final class NKMonitor: EventMonitor, Sendable { } func requestDidResume(_ request: Request) { - let level = NKLogFileManager.shared.minLevel - - if level >= .trace { + switch NKLogFileManager.shared.logLevel { + case .normal: nkLog(info: "Request started: \(request)") - } - - if level == .verbose { + case .verbose: let headers = request.request?.allHTTPHeaderFields?.description ?? "None" let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" nkLog(debug: "Headers: \(headers)") nkLog(debug: "Body: \(body)") + default: break } } @@ -38,32 +36,33 @@ final class NKMonitor: EventMonitor, Sendable { let account = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerAccount] { nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode) } + guard let date = self.nkCommonInstance.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") else { + return + } + let responseResultString = String("\(response.result)") + let responseDebugDescription = String("\(response.debugDescription)") + let responseAllHeaderFields = String("\(String(describing: response.response?.allHeaderFields))") - let level = NKLogFileManager.shared.minLevel - - if level >= .trace { + switch NKLogFileManager.shared.logLevel { + case .normal: + if let request = response.request { + let requestString = "\(request)" + nkLog(info: "Network response request: " + requestString + ", result: " + responseResultString) + } else { + nkLog(info: "Network response result: " + responseResultString) + } + case .trace: if case let .failure(error) = response.result { nkLog(info: "Response failed: \(error.localizedDescription)") } else { nkLog(info: "Response succeeded.") } - } - - if level >= .normal { - let resultStr = String(describing: response.result) - - if let request = response.request { - nkLog(info: "Full response from \(request): \(resultStr)") - } else { - nkLog(info: "Response result: \(resultStr)") - } - } + case .verbose: + nkLog(debug: "Network response result: \(date) " + responseDebugDescription) + nkLog(debug: "Network response all headers: \(date) " + responseAllHeaderFields) - if level == .verbose { - let headers = String(describing: response.response?.allHeaderFields) - let debugDescription = response.debugDescription - nkLog(debug: "Debug info: \(debugDescription)") - nkLog(debug: "Headers: \(headers)") + default: + break } } } diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index 1196d243..46c64e6f 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -11,11 +11,11 @@ public extension NextcloudKit { /// Configure the shared logger from NextcloudKit static func configureLogger(printLog: Bool = true, printColor: Bool = true, - minLevel: NKLogLevel = .normal, + logLevel: NKLogLevel = .normal, retentionDays: Int = 30) { NKLogFileManager.configure(printLog: printLog, printColor: printColor, - minLevel: minLevel, + logLevel: logLevel, retentionDays: retentionDays) } } From f5b2afc2da646e52fc05a8b0798cb057368f1e7c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 19:05:21 +0200 Subject: [PATCH 15/54] cod Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 12 +++---- Sources/NextcloudKit/NKMonitor.swift | 32 ++++++++++++++----- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index b736810f..7b6203cd 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -13,7 +13,7 @@ import Compression /// Defines the level of log verbosity. public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { /// Logging is disabled. - case off = 0 + case disabled = 0 /// Logs basic request lifecycle for developers (request started, response result). case trace = 1 @@ -30,7 +30,7 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { // For Picker display public var displayText: String { switch self { - case .off: return NSLocalizedString("_disabled_", comment: "") + case .disabled: return NSLocalizedString("_disabled_", comment: "") case .trace: return NSLocalizedString("_trace_", comment: "") case .normal: return NSLocalizedString("_normal_", comment: "") case .verbose: return NSLocalizedString("_verbose_", comment: "") @@ -77,7 +77,7 @@ public final class NKLogFileManager { private let logFileName = "log.txt" private let logDirectory: URL private var printLog: Bool - private var printColor: Bool = true + public var printColor: Bool = true public var logLevel: NKLogLevel private var currentLogDate: String private var retentionDays: Int @@ -151,7 +151,7 @@ public final class NKLogFileManager { } public func writeLog(_ message: String?) { - guard logLevel != .off else { return } + guard logLevel != .disabled else { return } guard let message = message else { return } let fileTimestamp = Self.stableTimestampString() @@ -177,11 +177,11 @@ public final class NKLogFileManager { } else if message.contains("[WARNING]") { return "🟡 " + message } else if message.contains("[INFO]") { - return "đŸŸĸ " + message + return "đŸ”ĩ " + message } else if message.contains("[DEBUG]") { return "âšĒī¸ " + message } else { - return "🔷 " + message + return "đŸŸŖ " + message } } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 10a51df3..a267406c 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -14,16 +14,27 @@ final class NKMonitor: EventMonitor, Sendable { } func requestDidResume(_ request: Request) { - switch NKLogFileManager.shared.logLevel { + let level = NKLogFileManager.shared.logLevel + + switch level { case .normal: + // General-purpose log: full Request description nkLog(info: "Request started: \(request)") + case .trace: + // Minimalist log: METHOD + URL + if let method = request.request?.httpMethod, + let url = request.request?.url?.absoluteString { + nkLog(info: "\(method) \(url)") + } case .verbose: + // Full dump: headers + body let headers = request.request?.allHTTPHeaderFields?.description ?? "None" let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" - + nkLog(debug: "Request started: \(request)") nkLog(debug: "Headers: \(headers)") nkLog(debug: "Body: \(body)") - default: break + default: + break } } @@ -52,15 +63,20 @@ final class NKMonitor: EventMonitor, Sendable { nkLog(info: "Network response result: " + responseResultString) } case .trace: - if case let .failure(error) = response.result { - nkLog(info: "Response failed: \(error.localizedDescription)") - } else { - nkLog(info: "Response succeeded.") + if let method = request.request?.httpMethod, + let url = request.request?.url?.absoluteString, + let code = response.response?.statusCode { + let statusSymbol: String + if NKLogFileManager.shared.printColor { + statusSymbol = (200..<300).contains(code) ? "đŸŸĸ" : "🔴" + } else { + statusSymbol = (200..<300).contains(code) ? "SUCCESS" : "ERROR" + } + nkLog(info: "\(statusSymbol) \(code) \(method) \(url)") } case .verbose: nkLog(debug: "Network response result: \(date) " + responseDebugDescription) nkLog(debug: "Network response all headers: \(date) " + responseAllHeaderFields) - default: break } From e5a6473d6d0d726fe9369c4ec3e0098efa059453 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 19:10:39 +0200 Subject: [PATCH 16/54] cleaning Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NKMonitor.swift | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index a267406c..5949345b 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -14,18 +14,10 @@ final class NKMonitor: EventMonitor, Sendable { } func requestDidResume(_ request: Request) { - let level = NKLogFileManager.shared.logLevel - - switch level { + switch NKLogFileManager.shared.logLevel { case .normal: // General-purpose log: full Request description nkLog(info: "Request started: \(request)") - case .trace: - // Minimalist log: METHOD + URL - if let method = request.request?.httpMethod, - let url = request.request?.url?.absoluteString { - nkLog(info: "\(method) \(url)") - } case .verbose: // Full dump: headers + body let headers = request.request?.allHTTPHeaderFields?.description ?? "None" From de9cabd038aa4f089875f50225afc962a4acb087 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 23:03:40 +0200 Subject: [PATCH 17/54] replace with responseData Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NextcloudKit+API.swift | 46 +++++++++---------- .../NextcloudKit/NextcloudKit+Comments.swift | 16 +++---- .../NextcloudKit/NextcloudKit+Download.swift | 4 +- Sources/NextcloudKit/NextcloudKit+E2EE.swift | 8 ++-- .../NextcloudKit/NextcloudKit+FilesLock.swift | 4 +- .../NextcloudKit/NextcloudKit+Livephoto.swift | 6 +-- Sources/NextcloudKit/NextcloudKit+Login.swift | 18 +++----- .../NextcloudKit+PushNotification.swift | 12 ++--- Sources/NextcloudKit/NextcloudKit+Share.swift | 4 +- .../NextcloudKit+ShareDownloadLimit.swift | 4 +- .../NextcloudKit/NextcloudKit+Upload.swift | 4 +- .../NextcloudKit/NextcloudKit+WebDAV.swift | 28 +++++------ 12 files changed, 75 insertions(+), 79 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+API.swift b/Sources/NextcloudKit/NextcloudKit+API.swift index cf03b12e..884bac29 100644 --- a/Sources/NextcloudKit/NextcloudKit+API.swift +++ b/Sources/NextcloudKit/NextcloudKit+API.swift @@ -34,7 +34,7 @@ public extension NextcloudKit { func checkServer(serverUrl: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrl.asUrl else { return options.queue.async { completion(nil, .urlError) } } @@ -42,7 +42,7 @@ public extension NextcloudKit { unauthorizedSession.request(url, method: .head, encoding: URLEncoding.default).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -224,7 +224,7 @@ public extension NextcloudKit { etag: String? = nil, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let nkSession = nkCommonInstance.getSession(account: account), var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { return options.queue.async { completion(account, nil, .urlError) } @@ -237,7 +237,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -250,7 +250,7 @@ public extension NextcloudKit { func downloadPreviewAsync(url: URL, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.downloadPreview(url: url, account: account, options: options) { account, responseData, error in continuation.resume(returning: (account: account, responseData: responseData, error: error)) @@ -269,7 +269,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ width: Int, _ height: Int, _ etag: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ width: Int, _ height: Int, _ etag: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "index.php/core/preview?fileId=\(fileId)&x=\(width)&y=\(height)&a=\(crop)&mode=\(cropMode)&forceIcon=\(forceIcon)&mimeFallback=\(mimeFallback)" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), @@ -285,7 +285,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -300,7 +300,7 @@ public extension NextcloudKit { func downloadPreviewAsync(fileId: String, etag: String? = nil, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, width: Int, height: Int, etag: String?, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, width: Int, height: Int, etag: String?, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.downloadPreview(fileId: fileId, etag: etag, account: account, options: options) { account, width, height, etag, responseData, error in continuation.resume(returning: (account: account, width: width, height: height, etag: etag, responseData: responseData, error: error)) @@ -318,7 +318,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ width: Int, _ height: Int, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ width: Int, _ height: Int, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "index.php/apps/files_trashbin/preview?fileId=\(fileId)&x=\(width)&y=\(height)&a=\(crop)&mode=\(cropMode)&forceIcon=\(forceIcon)&mimeFallback=\(mimeFallback)" guard let nkSession = nkCommonInstance.getSession(account: account), @@ -330,7 +330,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -349,7 +349,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ imageAvatar: UIImage?, _ imageOriginal: UIImage?, _ etag: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ imageAvatar: UIImage?, _ imageOriginal: UIImage?, _ etag: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "index.php/avatar/\(user)/\(sizeImage)" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), @@ -365,7 +365,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -449,7 +449,7 @@ public extension NextcloudKit { etag: String?, account: String, options: NKRequestOptions = NKRequestOptions(), - taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }) async -> (account: String, imageAvatar: UIImage?, imageOriginal: UIImage?, etag: String?, responseData: AFDataResponse?, error: NKError) { + taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }) async -> (account: String, imageAvatar: UIImage?, imageOriginal: UIImage?, etag: String?, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation { continuation in downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, @@ -468,7 +468,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrl.asUrl, let nkSession = nkCommonInstance.getSession(account: account), let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { @@ -478,7 +478,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -619,7 +619,7 @@ public extension NextcloudKit { func getCapabilities(account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "ocs/v1.php/cloud/capabilities" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), @@ -630,7 +630,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .get, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -643,7 +643,7 @@ public extension NextcloudKit { func getCapabilitiesAsync(account: String, options: NKRequestOptions = NKRequestOptions(), - taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }) async -> (account: String, responseData: AFDataResponse?, error: NKError) { + taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }) async -> (account: String, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation { continuation in getCapabilities(account: account, options: options, @@ -898,7 +898,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let nkSession = nkCommonInstance.getSession(account: account), let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { return options.queue.async { completion(account, nil, .urlError) } @@ -918,7 +918,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, method: method, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -970,7 +970,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "ocs/v2.php/apps/security_guard/diagnostics" /// options.contentType = "application/json" @@ -991,7 +991,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -1007,7 +1007,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in } - ) async -> (responseData: AFDataResponse?, error: NKError) { + ) async -> (responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation { continuation in sendClientDiagnosticsRemoteOperation( data: data, diff --git a/Sources/NextcloudKit/NextcloudKit+Comments.swift b/Sources/NextcloudKit/NextcloudKit+Comments.swift index 6f4074bc..ef074809 100644 --- a/Sources/NextcloudKit/NextcloudKit+Comments.swift +++ b/Sources/NextcloudKit/NextcloudKit+Comments.swift @@ -56,7 +56,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { /// options.contentType = "application/json" /// @@ -81,7 +81,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -98,7 +98,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { /// options.contentType = "application/xml" /// @@ -124,7 +124,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -140,7 +140,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let nkSession = nkCommonInstance.getSession(account: account), let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { return options.queue.async { completion(account, nil, .urlError) } @@ -153,7 +153,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -168,7 +168,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { /// options.contentType = "application/xml" /// @@ -194,7 +194,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Download.swift b/Sources/NextcloudKit/NextcloudKit+Download.swift index ae08bc5a..9574966b 100644 --- a/Sources/NextcloudKit/NextcloudKit+Download.swift +++ b/Sources/NextcloudKit/NextcloudKit+Download.swift @@ -14,7 +14,7 @@ public extension NextcloudKit { requestHandler: @escaping (_ request: DownloadRequest) -> Void = { _ in }, taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, progressHandler: @escaping (_ progress: Progress) -> Void = { _ in }, - completionHandler: @escaping (_ account: String, _ etag: String?, _ date: Date?, _ lenght: Int64, _ responseData: AFDownloadResponse?, _ afError: AFError?, _ nKError: NKError) -> Void) { + completionHandler: @escaping (_ account: String, _ etag: String?, _ date: Date?, _ lenght: Int64, _ responseData: AFDownloadResponse?, _ afError: AFError?, _ nKError: NKError) -> Void) { var convertible: URLConvertible? if serverUrlFileName is URL { convertible = serverUrlFileName as? URLConvertible @@ -38,7 +38,7 @@ public extension NextcloudKit { options.queue.async { taskHandler(task) } } .downloadProgress { progress in options.queue.async { progressHandler(progress) } - } .response(queue: self.nkCommonInstance.backgroundQueue) { response in + } .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let resultError = NKError(error: error, afResponse: response, responseData: nil) diff --git a/Sources/NextcloudKit/NextcloudKit+E2EE.swift b/Sources/NextcloudKit/NextcloudKit+E2EE.swift index 2a6985bd..913ec120 100644 --- a/Sources/NextcloudKit/NextcloudKit+E2EE.swift +++ b/Sources/NextcloudKit/NextcloudKit+E2EE.swift @@ -443,7 +443,7 @@ public extension NextcloudKit { func deleteE2EECertificate(account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { var version = "v1" if let optionsVesion = options.version { version = optionsVesion @@ -457,7 +457,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -471,7 +471,7 @@ public extension NextcloudKit { func deleteE2EEPrivateKey(account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { var version = "v1" if let optionsVesion = options.version { version = optionsVesion @@ -486,7 +486,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+FilesLock.swift b/Sources/NextcloudKit/NextcloudKit+FilesLock.swift index f80a3290..b7b75be1 100644 --- a/Sources/NextcloudKit/NextcloudKit+FilesLock.swift +++ b/Sources/NextcloudKit/NextcloudKit+FilesLock.swift @@ -12,7 +12,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrlFileName.encodedToUrl else { return options.queue.async { completion(account, nil, .urlError) } @@ -27,7 +27,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: method, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Livephoto.swift b/Sources/NextcloudKit/NextcloudKit+Livephoto.swift index 6a80bc51..08e7e641 100644 --- a/Sources/NextcloudKit/NextcloudKit+Livephoto.swift +++ b/Sources/NextcloudKit/NextcloudKit+Livephoto.swift @@ -11,7 +11,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrlfileNamePath.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account) else { return options.queue.async { completion(account, nil, .urlError) } @@ -35,7 +35,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -49,7 +49,7 @@ public extension NextcloudKit { func setLivephotoAsync(serverUrlfileNamePath: String, livePhotoFile: String, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.setLivephoto(serverUrlfileNamePath: serverUrlfileNamePath, livePhotoFile: livePhotoFile, account: account, options: options) { account, responseData, error in continuation.resume(returning: (account: account, responseData: responseData, error: error)) diff --git a/Sources/NextcloudKit/NextcloudKit+Login.swift b/Sources/NextcloudKit/NextcloudKit+Login.swift index 64288c8a..20deb2e6 100644 --- a/Sources/NextcloudKit/NextcloudKit+Login.swift +++ b/Sources/NextcloudKit/NextcloudKit+Login.swift @@ -14,7 +14,7 @@ public extension NextcloudKit { userAgent: String? = nil, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ token: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ token: String?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "ocs/v2.php/core/getapppassword" guard let url = self.nkCommonInstance.createStandardUrl(serverUrl: url, endpoint: endpoint, options: options) else { return options.queue.async { completion(nil, nil, .urlError) } @@ -35,18 +35,14 @@ public extension NextcloudKit { unauthorizedSession.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) options.queue.async { completion(nil, response, error) } - case .success(let xmlData): - if let data = xmlData { - let apppassword = NKDataFileXML(nkCommonInstance: self.nkCommonInstance).convertDataAppPassword(data: data) - options.queue.async { completion(apppassword, response, .success) } - } else { - options.queue.async { completion(nil, response, .xmlError) } - } + case .success(let data): + let apppassword = NKDataFileXML(nkCommonInstance: self.nkCommonInstance).convertDataAppPassword(data: data) + options.queue.async { completion(apppassword, response, .success) } } } } @@ -58,7 +54,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "ocs/v2.php/core/apppassword" guard let nkSession = nkCommonInstance.getSession(account: account), let url = self.nkCommonInstance.createStandardUrl(serverUrl: serverUrl, endpoint: endpoint, options: options) else { @@ -80,7 +76,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+PushNotification.swift b/Sources/NextcloudKit/NextcloudKit+PushNotification.swift index c01e6dae..02fcf2fb 100644 --- a/Sources/NextcloudKit/NextcloudKit+PushNotification.swift +++ b/Sources/NextcloudKit/NextcloudKit+PushNotification.swift @@ -54,7 +54,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "ocs/v2.php/apps/notifications/api/v2/push" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), @@ -65,7 +65,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -84,7 +84,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "devices?format=json" guard let nkSession = nkCommonInstance.getSession(account: account), let url = self.nkCommonInstance.createStandardUrl(serverUrl: proxyServerUrl, endpoint: endpoint, options: options), @@ -102,7 +102,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -120,7 +120,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "devices" guard let nkSession = nkCommonInstance.getSession(account: account), let url = self.nkCommonInstance.createStandardUrl(serverUrl: proxyServerUrl, endpoint: endpoint, options: options), @@ -137,7 +137,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .delete, parameters: parameters, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Share.swift b/Sources/NextcloudKit/NextcloudKit+Share.swift index 9082588b..1cbb6df8 100644 --- a/Sources/NextcloudKit/NextcloudKit+Share.swift +++ b/Sources/NextcloudKit/NextcloudKit+Share.swift @@ -405,7 +405,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { let endpoint = "ocs/v2.php/apps/files_sharing/api/v1/shares/\(idShare)" guard let nkSession = nkCommonInstance.getSession(account: account), let url = nkCommonInstance.createStandardUrl(serverUrl: nkSession.urlBase, endpoint: endpoint, options: options), @@ -416,7 +416,7 @@ public extension NextcloudKit { nkSession.sessionData.request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift index fde97bb2..4ac538ef 100644 --- a/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift +++ b/Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift @@ -92,7 +92,7 @@ public extension NextcloudKit { .sessionData .request(url, method: .delete, encoding: URLEncoding.default, headers: headers, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) - .response(queue: self.nkCommonInstance.backgroundQueue) { response in + .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -130,7 +130,7 @@ public extension NextcloudKit { .sessionData .request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)) .validate(statusCode: 200..<300) - .response(queue: self.nkCommonInstance.backgroundQueue) { response in + .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 3d3e2f69..7e0a3404 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -17,7 +17,7 @@ public extension NextcloudKit { requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in }, taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, progressHandler: @escaping (_ progress: Progress) -> Void = { _ in }, - completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ responseData: AFDataResponse?, _ afError: AFError?, _ nkError: NKError) -> Void) { + completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ responseData: AFDataResponse?, _ afError: AFError?, _ nkError: NKError) -> Void) { var convertible: URLConvertible? var size: Int64 = 0 if serverUrlFileName is URL { @@ -49,7 +49,7 @@ public extension NextcloudKit { }) .uploadProgress { progress in options.queue.async { progressHandler(progress) } size = progress.totalUnitCount - } .response(queue: self.nkCommonInstance.backgroundQueue) { response in + } .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let resultError = NKError(error: error, afResponse: response, responseData: response.data) diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index faf1dc61..e402f043 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -11,7 +11,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ ocId: String?, _ date: Date?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ ocId: String?, _ date: Date?, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrlFileName.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { @@ -29,7 +29,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -51,7 +51,7 @@ public extension NextcloudKit { func createFolderAsync(serverUrlFileName: String, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, ocId: String?, date: Date?, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, ocId: String?, date: Date?, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlFileName, account: account, options: options) { account, ocId, date, responseData, error in continuation.resume(returning: (account: account, ocId: ocId, date: date, responseData: responseData, error: error)) @@ -63,7 +63,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrlFileName.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { @@ -80,7 +80,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -93,7 +93,7 @@ public extension NextcloudKit { func deleteFileOrFolderAsync(serverUrlFileName: String, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.deleteFileOrFolder(serverUrlFileName: serverUrlFileName, account: account, options: options) { account, responseData, error in continuation.resume(returning: (account: account, responseData: responseData, error: error)) @@ -107,7 +107,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrlFileNameSource.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { @@ -131,7 +131,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -146,7 +146,7 @@ public extension NextcloudKit { serverUrlFileNameDestination: String, overwrite: Bool, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: overwrite, account: account, options: options) { account, responseData, error in continuation.resume(returning: (account: account, responseData: responseData, error: error)) @@ -160,7 +160,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { guard let url = serverUrlFileNameSource.encodedToUrl, let nkSession = nkCommonInstance.getSession(account: account), var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { @@ -185,7 +185,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) @@ -200,7 +200,7 @@ public extension NextcloudKit { serverUrlFileNameDestination: String, overwrite: Bool, account: String, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { + options: NKRequestOptions = NKRequestOptions()) async -> (account: String, responseData: AFDataResponse?, error: NKError) { await withUnsafeContinuation({ continuation in NextcloudKit.shared.copyFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: overwrite, account: account, options: options) { account, responseData, error in continuation.resume(returning: (account: account, responseData: responseData, error: error)) @@ -443,7 +443,7 @@ public extension NextcloudKit { account: String, options: NKRequestOptions = NKRequestOptions(), taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, - completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ responseData: AFDataResponse?, _ error: NKError) -> Void) { /// options.contentType = "application/xml" /// @@ -470,7 +470,7 @@ public extension NextcloudKit { nkSession.sessionData.request(urlRequest, interceptor: NKInterceptor(nkCommonInstance: nkCommonInstance)).validate(statusCode: 200..<300).onURLSessionTaskCreation { task in task.taskDescription = options.taskDescription taskHandler(task) - }.response(queue: self.nkCommonInstance.backgroundQueue) { response in + }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { case .failure(let error): let error = NKError(error: error, afResponse: response, responseData: response.data) From 7e076488994290bd9873788927673976008f2a11 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 7 Jun 2025 23:26:53 +0200 Subject: [PATCH 18/54] cod Signed-off-by: Marino Faggiana --- .../NextcloudKit/NextcloudKit+WebDAV.swift | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index e402f043..92959e0f 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -133,12 +133,24 @@ public extension NextcloudKit { taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in switch response.result { - case .failure(let error): + case .failure(let error): + if let afError = error.asAFError, case .responseSerializationFailed(let reason) = afError, case .inputDataNilOrZeroLength = reason { + // body nil, is .success + options.queue.async { + completion(account, response, .success) + } + return + } + let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } - } + options.queue.async { + completion(account, response, error) + } + case .success: + options.queue.async { + completion(account, response, .success) + } + } } } From 11df63b84a0e79b17f3e70ade4242a622995a232 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 09:39:24 +0200 Subject: [PATCH 19/54] fix Signed-off-by: Marino Faggiana --- .../NextcloudKit/NextcloudKit+WebDAV.swift | 121 ++++++++++++------ 1 file changed, 85 insertions(+), 36 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index 92959e0f..fb43a47a 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -30,21 +30,30 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in + let result: NKError + var date: Date? + let ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) + if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { + date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + } + switch response.result { case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, nil, nil, response, error) } - case .success: - let ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) - if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { - if let date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") { - options.queue.async { completion(account, ocId, date, response, .success) } - } else { - options.queue.async { completion(account, nil, nil, response, .invalidDate) } - } + if let afError = error.asAFError, + case .responseSerializationFailed(let reason) = afError, + case .inputDataNilOrZeroLength = reason { + // Treat empty body as success + result = .success } else { - options.queue.async { completion(account, nil, nil, response, .invalidDate) } + result = NKError(error: error, afResponse: response, responseData: response.data) } + + case .success: + result = .success + } + + options.queue.async { + completion(account, ocId, date, response, result) } } } @@ -81,12 +90,25 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in + let result: NKError + switch response.result { case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } + if let afError = error.asAFError, + case .responseSerializationFailed(let reason) = afError, + case .inputDataNilOrZeroLength = reason { + // Treat empty body as success + result = .success + } else { + result = NKError(error: error, afResponse: response, responseData: response.data) + } + case .success: - options.queue.async { completion(account, response, .success) } + result = .success + } + + options.queue.async { + completion(account, response, result) } } } @@ -132,25 +154,26 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in + let result: NKError + switch response.result { - case .failure(let error): - if let afError = error.asAFError, case .responseSerializationFailed(let reason) = afError, case .inputDataNilOrZeroLength = reason { - // body nil, is .success - options.queue.async { - completion(account, response, .success) - } - return + case .failure(let error): + if let afError = error.asAFError, + case .responseSerializationFailed(let reason) = afError, + case .inputDataNilOrZeroLength = reason { + // Treat empty body as success + result = .success + } else { + result = NKError(error: error, afResponse: response, responseData: response.data) } - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { - completion(account, response, error) - } - case .success: - options.queue.async { - completion(account, response, .success) - } - } + case .success: + result = .success + } + + options.queue.async { + completion(account, response, result) + } } } @@ -198,12 +221,25 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in + let result: NKError + switch response.result { case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } + if let afError = error.asAFError, + case .responseSerializationFailed(let reason) = afError, + case .inputDataNilOrZeroLength = reason { + // Treat empty body as success + result = .success + } else { + result = NKError(error: error, afResponse: response, responseData: response.data) + } + case .success: - options.queue.async { completion(account, response, .success) } + result = .success + } + + options.queue.async { + completion(account, response, result) } } } @@ -483,12 +519,25 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in + let result: NKError + switch response.result { case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } + if let afError = error.asAFError, + case .responseSerializationFailed(let reason) = afError, + case .inputDataNilOrZeroLength = reason { + // Treat empty body as success + result = .success + } else { + result = NKError(error: error, afResponse: response, responseData: response.data) + } + case .success: - options.queue.async { completion(account, response, .success) } + result = .success + } + + options.queue.async { + completion(account, response, result) } } } From 2e56778628658133324a985cca0ce32834caf9e9 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 10:15:44 +0200 Subject: [PATCH 20/54] cod Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NextcloudKit+API.swift | 18 ++-- Sources/NextcloudKit/NextcloudKit+Share.swift | 10 +-- .../NextcloudKit/NextcloudKit+WebDAV.swift | 85 ++----------------- Sources/NextcloudKit/NextcloudKit.swift | 17 ++++ 4 files changed, 32 insertions(+), 98 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+API.swift b/Sources/NextcloudKit/NextcloudKit+API.swift index 884bac29..1225f764 100644 --- a/Sources/NextcloudKit/NextcloudKit+API.swift +++ b/Sources/NextcloudKit/NextcloudKit+API.swift @@ -43,12 +43,9 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(response, error) } - case .success: - options.queue.async { completion(response, .success) } + let result = self.evaluateResponse(response) + options.queue.async { + completion(response, result) } } } @@ -72,12 +69,9 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } + let result = self.evaluateResponse(response) + options.queue.async { + completion(account, response, result) } } } diff --git a/Sources/NextcloudKit/NextcloudKit+Share.swift b/Sources/NextcloudKit/NextcloudKit+Share.swift index 1cbb6df8..dc9c874a 100644 --- a/Sources/NextcloudKit/NextcloudKit+Share.swift +++ b/Sources/NextcloudKit/NextcloudKit+Share.swift @@ -417,12 +417,10 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } + let result = self.evaluateResponse(response) + + options.queue.async { + completion(account, response, result) } } } diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index fb43a47a..1dd8b8a9 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -30,27 +30,12 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - let result: NKError var date: Date? let ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") } - - switch response.result { - case .failure(let error): - if let afError = error.asAFError, - case .responseSerializationFailed(let reason) = afError, - case .inputDataNilOrZeroLength = reason { - // Treat empty body as success - result = .success - } else { - result = NKError(error: error, afResponse: response, responseData: response.data) - } - - case .success: - result = .success - } + let result = self.evaluateResponse(response) options.queue.async { completion(account, ocId, date, response, result) @@ -90,22 +75,7 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - let result: NKError - - switch response.result { - case .failure(let error): - if let afError = error.asAFError, - case .responseSerializationFailed(let reason) = afError, - case .inputDataNilOrZeroLength = reason { - // Treat empty body as success - result = .success - } else { - result = NKError(error: error, afResponse: response, responseData: response.data) - } - - case .success: - result = .success - } + let result = self.evaluateResponse(response) options.queue.async { completion(account, response, result) @@ -154,22 +124,7 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - let result: NKError - - switch response.result { - case .failure(let error): - if let afError = error.asAFError, - case .responseSerializationFailed(let reason) = afError, - case .inputDataNilOrZeroLength = reason { - // Treat empty body as success - result = .success - } else { - result = NKError(error: error, afResponse: response, responseData: response.data) - } - - case .success: - result = .success - } + let result = self.evaluateResponse(response) options.queue.async { completion(account, response, result) @@ -221,22 +176,7 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - let result: NKError - - switch response.result { - case .failure(let error): - if let afError = error.asAFError, - case .responseSerializationFailed(let reason) = afError, - case .inputDataNilOrZeroLength = reason { - // Treat empty body as success - result = .success - } else { - result = NKError(error: error, afResponse: response, responseData: response.data) - } - - case .success: - result = .success - } + let result = self.evaluateResponse(response) options.queue.async { completion(account, response, result) @@ -519,22 +459,7 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - let result: NKError - - switch response.result { - case .failure(let error): - if let afError = error.asAFError, - case .responseSerializationFailed(let reason) = afError, - case .inputDataNilOrZeroLength = reason { - // Treat empty body as success - result = .success - } else { - result = NKError(error: error, afResponse: response, responseData: response.data) - } - - case .success: - result = .success - } + let result = self.evaluateResponse(response) options.queue.async { completion(account, response, result) diff --git a/Sources/NextcloudKit/NextcloudKit.swift b/Sources/NextcloudKit/NextcloudKit.swift index eb339707..0a885e01 100644 --- a/Sources/NextcloudKit/NextcloudKit.swift +++ b/Sources/NextcloudKit/NextcloudKit.swift @@ -188,4 +188,21 @@ open class NextcloudKit { reachabilityManager?.stopListening() } #endif + + /// Evaluates an Alamofire response and returns the appropriate NKError. + /// Treats `inputDataNilOrZeroLength` as `.success`. + func evaluateResponse(_ response: AFDataResponse) -> NKError { + switch response.result { + case .failure(let error): + if let afError = error.asAFError, + case .responseSerializationFailed(let reason) = afError, + case .inputDataNilOrZeroLength = reason { + return .success + } else { + return NKError(error: error, afResponse: response, responseData: response.data) + } + case .success: + return .success + } + } } From a544dadddfa4b501849557ed000cbf2df9915ca6 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 12:12:57 +0200 Subject: [PATCH 21/54] fix Signed-off-by: Marino Faggiana --- .../NextcloudKit/NextcloudKit+Upload.swift | 77 ++++++++----------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 7e0a3404..02d72e63 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -17,7 +17,7 @@ public extension NextcloudKit { requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in }, taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, progressHandler: @escaping (_ progress: Progress) -> Void = { _ in }, - completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ responseData: AFDataResponse?, _ afError: AFError?, _ nkError: NKError) -> Void) { + completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ responseData: AFDataResponse?, _ nkError: NKError) -> Void) { var convertible: URLConvertible? var size: Int64 = 0 if serverUrlFileName is URL { @@ -28,7 +28,7 @@ public extension NextcloudKit { guard let url = convertible, let nkSession = nkCommonInstance.getSession(account: account), var headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else { - return options.queue.async { completionHandler(account, nil, nil, nil, 0, nil, nil, .urlError) } + return options.queue.async { completionHandler(account, nil, nil, nil, 0, nil, .urlError) } } let fileNameLocalPathUrl = URL(fileURLWithPath: fileNameLocalPath) // Epoch of linux do not permitted negativ value @@ -50,34 +50,27 @@ public extension NextcloudKit { options.queue.async { progressHandler(progress) } size = progress.totalUnitCount } .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let resultError = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completionHandler(account, nil, nil, nil, 0, response, error, resultError) } - case .success: - var ocId: String?, etag: String? - if self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) != nil { - ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) - } else if self.nkCommonInstance.findHeader("fileid", allHeaderFields: response.response?.allHeaderFields) != nil { - ocId = self.nkCommonInstance.findHeader("fileid", allHeaderFields: response.response?.allHeaderFields) - } - if self.nkCommonInstance.findHeader("oc-etag", allHeaderFields: response.response?.allHeaderFields) != nil { - etag = self.nkCommonInstance.findHeader("oc-etag", allHeaderFields: response.response?.allHeaderFields) - } else if self.nkCommonInstance.findHeader("etag", allHeaderFields: response.response?.allHeaderFields) != nil { - etag = self.nkCommonInstance.findHeader("etag", allHeaderFields: response.response?.allHeaderFields) - } - if etag != nil { - etag = etag?.replacingOccurrences(of: "\"", with: "") - } - if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { - if let date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") { - options.queue.async { completionHandler(account, ocId, etag, date, size, response, nil, .success) } - } else { - options.queue.async { completionHandler(account, nil, nil, nil, 0, response, nil, .invalidDate) } - } - } else { - options.queue.async { completionHandler(account, nil, nil, nil, 0, response, nil, .invalidDate) } - } + var ocId: String?, etag: String?, date: Date? + if self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) != nil { + ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) + } else if self.nkCommonInstance.findHeader("fileid", allHeaderFields: response.response?.allHeaderFields) != nil { + ocId = self.nkCommonInstance.findHeader("fileid", allHeaderFields: response.response?.allHeaderFields) + } + if self.nkCommonInstance.findHeader("oc-etag", allHeaderFields: response.response?.allHeaderFields) != nil { + etag = self.nkCommonInstance.findHeader("oc-etag", allHeaderFields: response.response?.allHeaderFields) + } else if self.nkCommonInstance.findHeader("etag", allHeaderFields: response.response?.allHeaderFields) != nil { + etag = self.nkCommonInstance.findHeader("etag", allHeaderFields: response.response?.allHeaderFields) + } + if etag != nil { + etag = etag?.replacingOccurrences(of: "\"", with: "") + } + if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { + date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + } + let result = self.evaluateResponse(response) + + options.queue.async { + completionHandler(account, ocId, etag, date, size, response, result) } } @@ -114,10 +107,10 @@ public extension NextcloudKit { taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }, progressHandler: @escaping (_ totalBytesExpected: Int64, _ totalBytes: Int64, _ fractionCompleted: Double) -> Void = { _, _, _ in }, uploaded: @escaping (_ fileChunk: (fileName: String, size: Int64)) -> Void = { _ in }, - completion: @escaping (_ account: String, _ filesChunk: [(fileName: String, size: Int64)]?, _ file: NKFile?, _ afError: AFError?, _ error: NKError) -> Void) { + completion: @escaping (_ account: String, _ filesChunk: [(fileName: String, size: Int64)]?, _ file: NKFile?, _ error: NKError) -> Void) { guard let nkSession = nkCommonInstance.getSession(account: account) else { - return completion(account, nil, nil, nil, .urlError) + return completion(account, nil, nil, .urlError) } let fileNameLocalSize = self.nkCommonInstance.getFileSize(filePath: directory + "/" + fileName) let serverUrlChunkFolder = nkSession.urlBase + "/" + nkSession.dav + "/uploads/" + nkSession.userId + "/" + chunkFolder @@ -152,7 +145,7 @@ public extension NextcloudKit { if freeDisk < fileNameLocalSize * 4 { // It seems there is not enough space to send the file let error = NKError(errorCode: NKError.chunkNoEnoughMemory, errorDescription: "_chunk_enough_memory_") - return completion(account, nil, nil, nil, error) + return completion(account, nil, nil, error) } #endif @@ -172,10 +165,9 @@ public extension NextcloudKit { createFolder { error in guard error == .success else { - return completion(account, nil, nil, nil, NKError(errorCode: NKError.chunkCreateFolder, errorDescription: error.errorDescription)) + return completion(account, nil, nil, NKError(errorCode: NKError.chunkCreateFolder, errorDescription: error.errorDescription)) } var uploadNKError = NKError() - var uploadAFError: AFError? let outputDirectory = fileChunksOutputDirectory ?? directory self.nkCommonInstance.chunkedFile(inputDirectory: directory, outputDirectory: outputDirectory, fileName: fileName, chunkSize: chunkSize, filesChunk: filesChunk) { num in @@ -186,7 +178,7 @@ public extension NextcloudKit { if filesChunk.isEmpty { // The file for sending could not be created let error = NKError(errorCode: NKError.chunkFilesNull, errorDescription: "_chunk_files_null_") - return completion(account, nil, nil, nil, error) + return completion(account, nil, nil, error) } var filesChunkOutput = filesChunk start(filesChunkOutput) @@ -198,7 +190,7 @@ public extension NextcloudKit { if fileSize == 0 { // The file could not be sent let error = NKError(errorCode: NKError.chunkFileNull, errorDescription: "_chunk_file_null_") - return completion(account, nil, nil, .explicitlyCancelled, error) + return completion(account, nil, nil, error) } let semaphore = DispatchSemaphore(value: 0) self.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, account: account, options: options, requestHandler: { request in @@ -210,12 +202,11 @@ public extension NextcloudKit { let totalBytes = fileChunk.size let fractionCompleted = Double(totalBytes) / Double(totalBytesExpected) progressHandler(totalBytesExpected, totalBytes, fractionCompleted) - }) { _, _, _, _, _, _, afError, error in + }) { _, _, _, _, _, _, error in if error == .success { filesChunkOutput.removeFirst() uploaded(fileChunk) } - uploadAFError = afError uploadNKError = error semaphore.signal() } @@ -227,7 +218,7 @@ public extension NextcloudKit { } guard uploadNKError == .success else { - return completion(account, filesChunkOutput, nil, uploadAFError, NKError(errorCode: NKError.chunkFileUpload, errorDescription: uploadNKError.errorDescription)) + return completion(account, filesChunkOutput, nil, NKError(errorCode: NKError.chunkFileUpload, errorDescription: uploadNKError.errorDescription)) } // Assemble the chunks @@ -249,13 +240,13 @@ public extension NextcloudKit { self.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileName, overwrite: true, account: account, options: options) { _, _, error in guard error == .success else { - return completion(account, filesChunkOutput, nil, nil, NKError(errorCode: NKError.chunkMoveFile, errorDescription: error.errorDescription)) + return completion(account, filesChunkOutput, nil, NKError(errorCode: NKError.chunkMoveFile, errorDescription: error.errorDescription)) } self.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", account: account, options: NKRequestOptions(queue: self.nkCommonInstance.backgroundQueue)) { _, files, _, error in guard error == .success, let file = files?.first else { - return completion(account, filesChunkOutput, nil, nil, NKError(errorCode: NKError.chunkMoveFile, errorDescription: error.errorDescription)) + return completion(account, filesChunkOutput, nil, NKError(errorCode: NKError.chunkMoveFile, errorDescription: error.errorDescription)) } - return completion(account, filesChunkOutput, file, nil, error) + return completion(account, filesChunkOutput, file, error) } } } From ffcafd7f5bce4ef1be6951c58df9c69f50b26346 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 12:57:14 +0200 Subject: [PATCH 22/54] added .cancelled Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NKError.swift | 1 + Sources/NextcloudKit/NextcloudKit.swift | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Sources/NextcloudKit/NKError.swift b/Sources/NextcloudKit/NKError.swift index 829b59bd..bee02753 100644 --- a/Sources/NextcloudKit/NKError.swift +++ b/Sources/NextcloudKit/NKError.swift @@ -55,6 +55,7 @@ public struct NKError: Error, Equatable { public static let unauthorizedError = NKError(errorCode: 401, errorDescription: NSLocalizedString("_unauthorized_", value: "Unauthorized", comment: "")) public static let unavailableError = NKError(errorCode: 503, errorDescription: NSLocalizedString("_Unavailable_", value: "Unavailable", comment: "")) public static let forbiddenError = NKError(errorCode: 403, errorDescription: NSLocalizedString("_forbidden_", value: "Forbidden", comment: "")) + public static let cancelled = NKError(errorCode: -999, errorDescription: NSLocalizedString("_cancelled_", value: "Cancelled", comment: "")) public static let success = NKError(errorCode: 0, errorDescription: "") diff --git a/Sources/NextcloudKit/NextcloudKit.swift b/Sources/NextcloudKit/NextcloudKit.swift index 0a885e01..3ff2257c 100644 --- a/Sources/NextcloudKit/NextcloudKit.swift +++ b/Sources/NextcloudKit/NextcloudKit.swift @@ -192,6 +192,12 @@ open class NextcloudKit { /// Evaluates an Alamofire response and returns the appropriate NKError. /// Treats `inputDataNilOrZeroLength` as `.success`. func evaluateResponse(_ response: AFDataResponse) -> NKError { + if let afError = response.error?.asAFError { + if afError.isExplicitlyCancelledError { + return .cancelled + } + } + switch response.result { case .failure(let error): if let afError = error.asAFError, From d10e58922860c564d37a3a69c509deb666283908 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 14:46:55 +0200 Subject: [PATCH 23/54] error Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NKError.swift | 17 ++++----- .../NextcloudKit/NextcloudKit+Upload.swift | 36 +++++++++++-------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/Sources/NextcloudKit/NKError.swift b/Sources/NextcloudKit/NKError.swift index bee02753..a70a7ed2 100644 --- a/Sources/NextcloudKit/NKError.swift +++ b/Sources/NextcloudKit/NKError.swift @@ -34,14 +34,6 @@ extension OCSPath { public struct NKError: Error, Equatable { static let internalError = -9999 - // Chunk error - public static let chunkNoEnoughMemory = -9998 - public static let chunkMoveFile = -9997 - public static let chunkCreateFolder = -9996 - public static let chunkFilesNull = -9995 - public static let chunkFileNull = -9994 - public static let chunkFileUpload = -9993 - public let errorCode: Int public let errorDescription: String public let error: Error @@ -57,6 +49,15 @@ public struct NKError: Error, Equatable { public static let forbiddenError = NKError(errorCode: 403, errorDescription: NSLocalizedString("_forbidden_", value: "Forbidden", comment: "")) public static let cancelled = NKError(errorCode: -999, errorDescription: NSLocalizedString("_cancelled_", value: "Cancelled", comment: "")) + public static let uploadIncomplete = NKError(errorCode: -9992, errorDescription: NSLocalizedString("_upload_incomplete_", value: "Upload incomplete", comment: "")) + + public static let errorChunkFileUpload = NKError(errorCode: -9993, errorDescription: NSLocalizedString("_upload_incomplete_", value: "Upload incomplete", comment: "")) + public static let errorChunkFileNull = NKError(errorCode: -9994, errorDescription: NSLocalizedString("_error_file_null_", value: "File not found", comment: "")) + public static let errorChunkFilesEmpty = NKError(errorCode: -9995, errorDescription: NSLocalizedString("_chunk_files_empty_", value: "Files not found", comment: "")) + public static let errorChunkCreateFolder = NKError(errorCode: -9996, errorDescription: NSLocalizedString("_error_create_folder_", value: "Create folder error", comment: "")) + public static let errorChunkMoveFile = NKError(errorCode: -9997, errorDescription: NSLocalizedString("_error_move_folder_", value: "Move file error", comment: "")) + public static let errorChunkNoEnoughMemory = NKError(errorCode: -9998, errorDescription: NSLocalizedString("_no_enough_memory_", value: "No enough memory", comment: "")) + public static let success = NKError(errorCode: 0, errorDescription: "") public static func getErrorDescription(for code: Int) -> String? { diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 02d72e63..cbf8fa4a 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -19,7 +19,9 @@ public extension NextcloudKit { progressHandler: @escaping (_ progress: Progress) -> Void = { _ in }, completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ responseData: AFDataResponse?, _ nkError: NKError) -> Void) { var convertible: URLConvertible? - var size: Int64 = 0 + var uploadedSize: Int64 = 0 + var uploadCompleted = false + if serverUrlFileName is URL { convertible = serverUrlFileName as? URLConvertible } else if serverUrlFileName is String || serverUrlFileName is NSString { @@ -47,10 +49,13 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription options.queue.async { taskHandler(task) } }) .uploadProgress { progress in + uploadedSize = progress.totalUnitCount + uploadCompleted = progress.fractionCompleted == 1.0 options.queue.async { progressHandler(progress) } - size = progress.totalUnitCount } .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in var ocId: String?, etag: String?, date: Date? + var result: NKError + if self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) != nil { ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) } else if self.nkCommonInstance.findHeader("fileid", allHeaderFields: response.response?.allHeaderFields) != nil { @@ -67,10 +72,16 @@ public extension NextcloudKit { if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") } - let result = self.evaluateResponse(response) + + if !uploadCompleted { + nkLog(warning: "Upload incomplete: only \(uploadedSize) bytes sent.") + result = .uploadIncomplete // Definisci un errore custom se vuoi + } else { + result = self.evaluateResponse(response) + } options.queue.async { - completionHandler(account, ocId, etag, date, size, response, result) + completionHandler(account, ocId, etag, date, uploadedSize, response, result) } } @@ -144,8 +155,7 @@ public extension NextcloudKit { #if os(visionOS) || os(iOS) if freeDisk < fileNameLocalSize * 4 { // It seems there is not enough space to send the file - let error = NKError(errorCode: NKError.chunkNoEnoughMemory, errorDescription: "_chunk_enough_memory_") - return completion(account, nil, nil, error) + return completion(account, nil, nil, .errorChunkNoEnoughMemory) } #endif @@ -165,7 +175,7 @@ public extension NextcloudKit { createFolder { error in guard error == .success else { - return completion(account, nil, nil, NKError(errorCode: NKError.chunkCreateFolder, errorDescription: error.errorDescription)) + return completion(account, nil, nil, .errorChunkCreateFolder) } var uploadNKError = NKError() @@ -177,8 +187,7 @@ public extension NextcloudKit { } completion: { filesChunk in if filesChunk.isEmpty { // The file for sending could not be created - let error = NKError(errorCode: NKError.chunkFilesNull, errorDescription: "_chunk_files_null_") - return completion(account, nil, nil, error) + return completion(account, nil, nil, .errorChunkFilesEmpty) } var filesChunkOutput = filesChunk start(filesChunkOutput) @@ -189,8 +198,7 @@ public extension NextcloudKit { let fileSize = self.nkCommonInstance.getFileSize(filePath: fileNameLocalPath) if fileSize == 0 { // The file could not be sent - let error = NKError(errorCode: NKError.chunkFileNull, errorDescription: "_chunk_file_null_") - return completion(account, nil, nil, error) + return completion(account, nil, nil, .errorChunkFileNull) } let semaphore = DispatchSemaphore(value: 0) self.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, account: account, options: options, requestHandler: { request in @@ -218,7 +226,7 @@ public extension NextcloudKit { } guard uploadNKError == .success else { - return completion(account, filesChunkOutput, nil, NKError(errorCode: NKError.chunkFileUpload, errorDescription: uploadNKError.errorDescription)) + return completion(account, filesChunkOutput, nil, .errorChunkFileUpload) } // Assemble the chunks @@ -240,11 +248,11 @@ public extension NextcloudKit { self.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileName, overwrite: true, account: account, options: options) { _, _, error in guard error == .success else { - return completion(account, filesChunkOutput, nil, NKError(errorCode: NKError.chunkMoveFile, errorDescription: error.errorDescription)) + return completion(account, filesChunkOutput, nil,.errorChunkMoveFile) } self.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", account: account, options: NKRequestOptions(queue: self.nkCommonInstance.backgroundQueue)) { _, files, _, error in guard error == .success, let file = files?.first else { - return completion(account, filesChunkOutput, nil, NKError(errorCode: NKError.chunkMoveFile, errorDescription: error.errorDescription)) + return completion(account, filesChunkOutput, nil, .errorChunkMoveFile) } return completion(account, filesChunkOutput, file, error) } From 1e7fbd10a3bb498f7719f0aeec2a94231fb2ff6b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 15:07:22 +0200 Subject: [PATCH 24/54] code Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NextcloudKit+Upload.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index cbf8fa4a..433d1899 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -72,13 +72,18 @@ public extension NextcloudKit { if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") } - + + /* if !uploadCompleted { - nkLog(warning: "Upload incomplete: only \(uploadedSize) bytes sent.") - result = .uploadIncomplete // Definisci un errore custom se vuoi + nkLog(error: "Upload incomplete: only \(uploadedSize) bytes sent.") + result = .uploadIncomplete } else { result = self.evaluateResponse(response) } + */ + + + result = self.evaluateResponse(response) options.queue.async { completionHandler(account, ocId, etag, date, uploadedSize, response, result) From b9a10e12c6d639d48e84982755a4b210d6c8ee86 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 15:10:12 +0200 Subject: [PATCH 25/54] code Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NextcloudKit+Upload.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 433d1899..5304debc 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -72,18 +72,13 @@ public extension NextcloudKit { if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") } - - /* + if !uploadCompleted { nkLog(error: "Upload incomplete: only \(uploadedSize) bytes sent.") result = .uploadIncomplete } else { result = self.evaluateResponse(response) } - */ - - - result = self.evaluateResponse(response) options.queue.async { completionHandler(account, ocId, etag, date, uploadedSize, response, result) From f29282dfa8c3592d5377de9d19226e660668c405 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 16:16:29 +0200 Subject: [PATCH 26/54] comments Signed-off-by: Marino Faggiana --- .../NextcloudKit/NextcloudKit+Comments.swift | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+Comments.swift b/Sources/NextcloudKit/NextcloudKit+Comments.swift index ef074809..05c35d7f 100644 --- a/Sources/NextcloudKit/NextcloudKit+Comments.swift +++ b/Sources/NextcloudKit/NextcloudKit+Comments.swift @@ -82,12 +82,10 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } + let result = self.evaluateResponse(response) + + options.queue.async { + completion(account, response, result) } } } @@ -125,12 +123,10 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } + let result = self.evaluateResponse(response) + + options.queue.async { + completion(account, response, result) } } } @@ -154,12 +150,10 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } + let result = self.evaluateResponse(response) + + options.queue.async { + completion(account, response, result) } } } @@ -195,12 +189,10 @@ public extension NextcloudKit { task.taskDescription = options.taskDescription taskHandler(task) }.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in - switch response.result { - case .failure(let error): - let error = NKError(error: error, afResponse: response, responseData: response.data) - options.queue.async { completion(account, response, error) } - case .success: - options.queue.async { completion(account, response, .success) } + let result = self.evaluateResponse(response) + + options.queue.async { + completion(account, response, result) } } } From d7f67d91b5050502df6aa8bd52d8e05010a9adc8 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 17:12:28 +0200 Subject: [PATCH 27/54] typeTag: typeTag Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 4 +-- .../NextcloudKit/Log/NKLogFileManager.swift | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 24506073..8957ef02 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -33,6 +33,6 @@ public func nkLog(error message: String) { /// - message: The message to log. /// - level: The minimum level required for the message to be recorded. @inlinable -public func nkLog(tag: String, message: String) { - NKLogFileManager.shared.writeLog(tag: tag, message: message) +public func nkLog(tag: String, typeTag: NKLogTypeTag = .debug, message: String) { + NKLogFileManager.shared.writeLog(tag: tag, typeTag: typeTag, message: message) } diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 7b6203cd..b7a579f1 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -43,6 +43,14 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { } } +/// Type for writes a tagged log message +public enum NKLogTypeTag: String { + case debug = "[DEBUG]" + case info = "[INFO]" + case warning = "[WARNING]" + case error = "[ERROR]" +} + /// A logger that writes log messages to a file in a subdirectory of the user's Documents folder, /// rotates the log daily, and compresses old logs with GZip. /// Compatible with iOS 13.0+ and Swift 6. @@ -144,10 +152,11 @@ public final class NKLogFileManager { /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). /// - message: The log message content. /// - level: The minimum level required for this message to be written. - public func writeLog(tag: String, message: String) { + public func writeLog(tag: String, typeTag: NKLogTypeTag, message: String) { guard !tag.isEmpty else { return } + let emojiColored = printColor ? emojiColored(typeTag.rawValue) : "" - writeLog("[\(tag.uppercased())] \(message)") + writeLog("\(emojiColored)[\(tag.uppercased())] \(message)") } public func writeLog(_ message: String?) { @@ -160,7 +169,7 @@ public final class NKLogFileManager { if printLog { let consoleLine = printColor - ? emojiColored("\(consoleTimestamp) \(message)") + ? emojiColored(message) + "\(consoleTimestamp) \(message)" : "\(consoleTimestamp) \(message)" print(consoleLine) } @@ -173,15 +182,15 @@ public final class NKLogFileManager { private func emojiColored(_ message: String) -> String { if message.contains("[ERROR]") { - return "🔴 " + message + return "🔴 " } else if message.contains("[WARNING]") { - return "🟡 " + message + return "🟡 " } else if message.contains("[INFO]") { - return "đŸ”ĩ " + message + return "đŸ”ĩ " } else if message.contains("[DEBUG]") { - return "âšĒī¸ " + message + return "âšĒī¸ " } else { - return "đŸŸŖ " + message + return "đŸŸŖ " } } From 9587ecdb757c30da009583827afb73fc5bcd1454 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 8 Jun 2025 17:26:53 +0200 Subject: [PATCH 28/54] [SUCCESS] Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index b7a579f1..d8785b51 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -49,6 +49,7 @@ public enum NKLogTypeTag: String { case info = "[INFO]" case warning = "[WARNING]" case error = "[ERROR]" + case success = "[SUCCESS]" } /// A logger that writes log messages to a file in a subdirectory of the user's Documents folder, @@ -183,6 +184,8 @@ public final class NKLogFileManager { private func emojiColored(_ message: String) -> String { if message.contains("[ERROR]") { return "🔴 " + } else if message.contains("[SUCCESS]") { + return "đŸŸĸ " } else if message.contains("[WARNING]") { return "🟡 " } else if message.contains("[INFO]") { From 138b5fa57df5d4693c646b35c188946968e25e78 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 09:44:37 +0200 Subject: [PATCH 29/54] cod Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 5 +++++ Sources/NextcloudKit/Log/NKLogFileManager.swift | 8 +++++++- Sources/NextcloudKit/NKMonitor.swift | 8 ++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 8957ef02..746bdd1b 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -27,6 +27,11 @@ public func nkLog(error message: String) { NKLogFileManager.shared.writeLog(error: message) } +@inlinable +public func nkLog(network message: String) { + NKLogFileManager.shared.writeLog(error: message) +} + /// Logs a custom tagged message at the specified level. /// - Parameters: /// - tag: A custom uppercase tag, e.g. \"UPLOAD\", \"SYNC\", \"AUTH\". diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index d8785b51..5d86de21 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -148,6 +148,10 @@ public final class NKLogFileManager { writeLog("[ERROR] \(message)") } + public func writeLog(network message: String) { + writeLog("[NETWORK] \(message)") + } + /// Writes a tagged log message with a specific log level. /// - Parameters: /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). @@ -192,8 +196,10 @@ public final class NKLogFileManager { return "đŸ”ĩ " } else if message.contains("[DEBUG]") { return "âšĒī¸ " - } else { + } else if message.contains("[NETWORK]") { return "đŸŸŖ " + } else { + return "" } } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 5949345b..bbf35063 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -58,13 +58,13 @@ final class NKMonitor: EventMonitor, Sendable { if let method = request.request?.httpMethod, let url = request.request?.url?.absoluteString, let code = response.response?.statusCode { - let statusSymbol: String + let response: String if NKLogFileManager.shared.printColor { - statusSymbol = (200..<300).contains(code) ? "đŸŸĸ" : "🔴" + response = (200..<300).contains(code) ? "đŸŸĸ" : "🔴" } else { - statusSymbol = (200..<300).contains(code) ? "SUCCESS" : "ERROR" + response = (200..<300).contains(code) ? "SUCCESS" : "ERROR" } - nkLog(info: "\(statusSymbol) \(code) \(method) \(url)") + nkLog(network: "\(code) \(method) \(url) \(response)") } case .verbose: nkLog(debug: "Network response result: \(date) " + responseDebugDescription) From 342bdfadb5949fe85f86292f8d721ad32219e9c5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 10:09:14 +0200 Subject: [PATCH 30/54] cod Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 2 +- .../NextcloudKit/Log/NKLogFileManager.swift | 75 +++---------------- .../NextcloudKit/NextcloudKit+Logging.swift | 6 +- 3 files changed, 12 insertions(+), 71 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 746bdd1b..b85cc425 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -29,7 +29,7 @@ public func nkLog(error message: String) { @inlinable public func nkLog(network message: String) { - NKLogFileManager.shared.writeLog(error: message) + NKLogFileManager.shared.writeLog(network: message) } /// Logs a custom tagged message at the specified level. diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 5d86de21..fd5b61b9 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -2,12 +2,7 @@ // SPDX-FileCopyrightText: 2025 Marino Faggiana // SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: Nextcloud GmbH -// SPDX-FileCopyrightText: 2025 Marino Faggiana -// SPDX-License-Identifier: GPL-3.0-or-later - import Foundation -import Compression /// Defines the severity level of a log message. /// Defines the level of log verbosity. @@ -67,13 +62,11 @@ public final class NKLogFileManager { /// - printLog: Whether to print logs to the console. /// - printColor: Whether to print logs to the console with the emojiColored /// - minLevel: The minimum log level to be recorded. - /// - retentionDays: Number of days to keep compressed logs. public static func configure(printLog: Bool = true, printColor: Bool = true, - logLevel: NKLogLevel = .normal, - retentionDays: Int = 30) { - shared.setConfiguration(printLog: printLog, printColor: printColor, logLevel: logLevel, retentionDays: retentionDays) + logLevel: NKLogLevel = .normal) { + shared.setConfiguration(printLog: printLog, printColor: printColor, logLevel: logLevel) } /// Returns the file URL of the currently active log file. @@ -83,22 +76,20 @@ public final class NKLogFileManager { // MARK: - Configuration - private let logFileName = "log.txt" + private let logFileName = "log.md" private let logDirectory: URL private var printLog: Bool public var printColor: Bool = true public var logLevel: NKLogLevel private var currentLogDate: String - private var retentionDays: Int private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) private let fileManager = FileManager.default // MARK: - Initialization - private init(printLog: Bool = true, logLevel: NKLogLevel = .normal, retentionDays: Int = 30) { + private init(printLog: Bool = true, logLevel: NKLogLevel = .normal) { self.printLog = printLog self.logLevel = logLevel - self.retentionDays = retentionDays let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let logsFolder = documents.appendingPathComponent("Logs", isDirectory: true) @@ -116,11 +107,10 @@ public final class NKLogFileManager { /// - minLevel: The minimum log level. /// - retentionDays: Number of days to retain compressed logs. /// - private func setConfiguration(printLog: Bool, printColor: Bool, logLevel: NKLogLevel, retentionDays: Int) { + private func setConfiguration(printLog: Bool, printColor: Bool, logLevel: NKLogLevel) { self.printLog = printLog self.printColor = printColor self.logLevel = logLevel - self.retentionDays = retentionDays } // MARK: - Public API @@ -197,7 +187,7 @@ public final class NKLogFileManager { } else if message.contains("[DEBUG]") { return "âšĒī¸ " } else if message.contains("[NETWORK]") { - return "đŸŸŖ " + return "🌐 " } else { return "" } @@ -215,43 +205,21 @@ public final class NKLogFileManager { private func rotateLog(for date: String) { let currentPath = logDirectory.appendingPathComponent(logFileName) - let rotatedPath = logDirectory.appendingPathComponent("log-\(date)") - let compressedPath = rotatedPath.appendingPathExtension("gz") + let rotatedPath = logDirectory.appendingPathComponent("log-\(date).md") do { if fileManager.fileExists(atPath: currentPath.path) { try fileManager.moveItem(at: currentPath, to: rotatedPath) - try compressFile(at: rotatedPath, to: compressedPath) - try fileManager.removeItem(at: rotatedPath) } + // Create a new empty log file for today try Data().write(to: currentPath) - cleanupOldLogs() + } catch { print("Log rotation failed: \(error)") } } - private func cleanupOldLogs() { - let calendar = Calendar.current - let now = Date() - - guard let enumerator = try? fileManager.contentsOfDirectory(at: logDirectory, includingPropertiesForKeys: [.contentModificationDateKey], options: [.skipsHiddenFiles]) else { - return - } - - for fileURL in enumerator { - guard fileURL.pathExtension == "gz" else { continue } - - if let attrs = try? fileURL.resourceValues(forKeys: [.contentModificationDateKey]), - let modDate = attrs.contentModificationDate, - let expiryDate = calendar.date(byAdding: .day, value: -retentionDays, to: now), - modDate < expiryDate { - try? fileManager.removeItem(at: fileURL) - } - } - } - // MARK: - Log Writing private func appendToLog(_ message: String) { @@ -270,31 +238,6 @@ public final class NKLogFileManager { } } - // MARK: - Compression - - private func compressFile(at inputURL: URL, to outputURL: URL) throws { - let inputData = try Data(contentsOf: inputURL) - var compressedBuffer = [UInt8](repeating: 0, count: inputData.count) - - let compressedSize = inputData.withUnsafeBytes { srcPtr in - compression_encode_buffer( - &compressedBuffer, - compressedBuffer.count, - srcPtr.baseAddress!.assumingMemoryBound(to: UInt8.self), - inputData.count, - nil, - COMPRESSION_ZLIB - ) - } - - guard compressedSize > 0 else { - throw NSError(domain: "CompressionError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Compression failed"]) - } - - let compressedData = Data(bytes: compressedBuffer, count: compressedSize) - try compressedData.write(to: outputURL) - } - // MARK: - Date Helpers private static func currentDateString() -> String { diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index 46c64e6f..36482727 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -11,11 +11,9 @@ public extension NextcloudKit { /// Configure the shared logger from NextcloudKit static func configureLogger(printLog: Bool = true, printColor: Bool = true, - logLevel: NKLogLevel = .normal, - retentionDays: Int = 30) { + logLevel: NKLogLevel = .normal) { NKLogFileManager.configure(printLog: printLog, printColor: printColor, - logLevel: logLevel, - retentionDays: retentionDays) + logLevel: logLevel) } } From 249db9c2c5d774dff56821996c828ea62276471e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 10:16:37 +0200 Subject: [PATCH 31/54] fix Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index fd5b61b9..22bbf149 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -160,12 +160,11 @@ public final class NKLogFileManager { let fileTimestamp = Self.stableTimestampString() let consoleTimestamp = Self.localizedTimestampString() - let fullMessage = "\(fileTimestamp) \(message)\n" + let emoji = printColor ? emojiColored(message) : "" + let fullMessage = "\(fileTimestamp) \(emoji)\(message)\n" if printLog { - let consoleLine = printColor - ? emojiColored(message) + "\(consoleTimestamp) \(message)" - : "\(consoleTimestamp) \(message)" + let consoleLine = "\(consoleTimestamp) \(emoji)\(message)" print(consoleLine) } From 9b3e3736327190592acfd1d0e6e8c755a0f7f53f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 10:30:54 +0200 Subject: [PATCH 32/54] cod Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 46 +++++++------------ Sources/NextcloudKit/NKMonitor.swift | 2 + .../NextcloudKit/NextcloudKit+Logging.swift | 8 +--- 3 files changed, 20 insertions(+), 36 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 22bbf149..3772993f 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -59,14 +59,10 @@ public final class NKLogFileManager { /// Configures the shared logger instance. /// - Parameters: - /// - printLog: Whether to print logs to the console. - /// - printColor: Whether to print logs to the console with the emojiColored /// - minLevel: The minimum log level to be recorded. - public static func configure(printLog: Bool = true, - printColor: Bool = true, - logLevel: NKLogLevel = .normal) { - shared.setConfiguration(printLog: printLog, printColor: printColor, logLevel: logLevel) + public static func configure(logLevel: NKLogLevel = .normal) { + shared.setConfiguration(logLevel: logLevel) } /// Returns the file URL of the currently active log file. @@ -76,10 +72,8 @@ public final class NKLogFileManager { // MARK: - Configuration - private let logFileName = "log.md" + private let logFileName = "log.txt" private let logDirectory: URL - private var printLog: Bool - public var printColor: Bool = true public var logLevel: NKLogLevel private var currentLogDate: String private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) @@ -87,8 +81,7 @@ public final class NKLogFileManager { // MARK: - Initialization - private init(printLog: Bool = true, logLevel: NKLogLevel = .normal) { - self.printLog = printLog + private init(logLevel: NKLogLevel = .normal) { self.logLevel = logLevel let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! @@ -102,14 +95,9 @@ public final class NKLogFileManager { /// Sets configuration parameters for the logger. /// - Parameters: - /// - printLog: Whether to print logs to the console. - /// - printColor: Whether to print logs to the console with the emojiColored - /// - minLevel: The minimum log level. - /// - retentionDays: Number of days to retain compressed logs. + /// - logLevel: The log level. /// - private func setConfiguration(printLog: Bool, printColor: Bool, logLevel: NKLogLevel) { - self.printLog = printLog - self.printColor = printColor + private func setConfiguration(logLevel: NKLogLevel) { self.logLevel = logLevel } @@ -149,28 +137,26 @@ public final class NKLogFileManager { /// - level: The minimum level required for this message to be written. public func writeLog(tag: String, typeTag: NKLogTypeTag, message: String) { guard !tag.isEmpty else { return } - let emojiColored = printColor ? emojiColored(typeTag.rawValue) : "" + let emojiColored = emojiColored(typeTag.rawValue) writeLog("\(emojiColored)[\(tag.uppercased())] \(message)") } public func writeLog(_ message: String?) { - guard logLevel != .disabled else { return } - guard let message = message else { return } + guard logLevel != .disabled, let message = message else { return } let fileTimestamp = Self.stableTimestampString() let consoleTimestamp = Self.localizedTimestampString() - let emoji = printColor ? emojiColored(message) : "" - let fullMessage = "\(fileTimestamp) \(emoji)\(message)\n" + let line = "[\(consoleTimestamp)] \(message)" + let fileLine = "\(fileTimestamp) \(message)\n" - if printLog { - let consoleLine = "\(consoleTimestamp) \(emoji)\(message)" - print(consoleLine) - } + let emoji = emojiColored(message) + let consoleLine = "\(emoji)\(line)" + print(consoleLine) - logQueue.async(flags: .barrier) { + logQueue.async { self.checkForRotation() - self.appendToLog(fullMessage) + self.appendToLog(fileLine) } } @@ -204,7 +190,7 @@ public final class NKLogFileManager { private func rotateLog(for date: String) { let currentPath = logDirectory.appendingPathComponent(logFileName) - let rotatedPath = logDirectory.appendingPathComponent("log-\(date).md") + let rotatedPath = logDirectory.appendingPathComponent("log-\(date).txt") do { if fileManager.fileExists(atPath: currentPath.path) { diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index bbf35063..31c7656e 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -58,6 +58,7 @@ final class NKMonitor: EventMonitor, Sendable { if let method = request.request?.httpMethod, let url = request.request?.url?.absoluteString, let code = response.response?.statusCode { + /* let response: String if NKLogFileManager.shared.printColor { response = (200..<300).contains(code) ? "đŸŸĸ" : "🔴" @@ -65,6 +66,7 @@ final class NKMonitor: EventMonitor, Sendable { response = (200..<300).contains(code) ? "SUCCESS" : "ERROR" } nkLog(network: "\(code) \(method) \(url) \(response)") + */ } case .verbose: nkLog(debug: "Network response result: \(date) " + responseDebugDescription) diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index 36482727..2371b31f 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -9,11 +9,7 @@ public extension NextcloudKit { } /// Configure the shared logger from NextcloudKit - static func configureLogger(printLog: Bool = true, - printColor: Bool = true, - logLevel: NKLogLevel = .normal) { - NKLogFileManager.configure(printLog: printLog, - printColor: printColor, - logLevel: logLevel) + static func configureLogger(logLevel: NKLogLevel = .normal) { + NKLogFileManager.configure(logLevel: logLevel) } } From 225253f3161d4c4bfd7bc89d936c7f8c2d230bcb Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 10:44:48 +0200 Subject: [PATCH 33/54] cod Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 26 ++++++++++++++++--- Sources/NextcloudKit/NKMonitor.swift | 9 +------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 3772993f..41995b2a 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -77,6 +77,7 @@ public final class NKLogFileManager { public var logLevel: NKLogLevel private var currentLogDate: String private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) + private let rotationQueue = DispatchQueue(label: "LogRotationQueue") private let fileManager = FileManager.default // MARK: - Initialization @@ -142,20 +143,37 @@ public final class NKLogFileManager { writeLog("\(emojiColored)[\(tag.uppercased())] \(message)") } + /// Writes a log message to both the console and the log file. + /// Emojis and keyword replacements (e.g. [SUCCESS] -> đŸŸĸ) are only applied to the console output. + /// The log file is plain and suitable for parsing. Rotation is handled before writing. + /// + /// - Parameter message: The log message to record. public func writeLog(_ message: String?) { guard logLevel != .disabled, let message = message else { return } + // Generate timestamps for file and console let fileTimestamp = Self.stableTimestampString() let consoleTimestamp = Self.localizedTimestampString() - let line = "[\(consoleTimestamp)] \(message)" + + // Prepare the clean file line (without emojis or replacements) let fileLine = "\(fileTimestamp) \(message)\n" - let emoji = emojiColored(message) - let consoleLine = "\(emoji)\(line)" + // Prepare the console line with emoji prefix and keyword substitution + let emojiPrefix = emojiColored(message) + let visualMessage = message + .replacingOccurrences(of: "[SUCCESS]", with: "đŸŸĸ") + .replacingOccurrences(of: "[ERROR]", with: "🔴") + + let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emojiPrefix)\(visualMessage)" print(consoleLine) - logQueue.async { + // Ensure log rotation is completed before writing to the file + rotationQueue.sync { self.checkForRotation() + } + + // Write to the log file asynchronously + logQueue.async { self.appendToLog(fileLine) } } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 31c7656e..d2dd5bc3 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -58,15 +58,8 @@ final class NKMonitor: EventMonitor, Sendable { if let method = request.request?.httpMethod, let url = request.request?.url?.absoluteString, let code = response.response?.statusCode { - /* - let response: String - if NKLogFileManager.shared.printColor { - response = (200..<300).contains(code) ? "đŸŸĸ" : "🔴" - } else { - response = (200..<300).contains(code) ? "SUCCESS" : "ERROR" - } + let response = (200..<300).contains(code) ? "SUCCESS" : "ERROR" nkLog(network: "\(code) \(method) \(url) \(response)") - */ } case .verbose: nkLog(debug: "Network response result: \(date) " + responseDebugDescription) From 05e332c635fb09a48c3dc878c140f96f7c444cb4 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 10:55:14 +0200 Subject: [PATCH 34/54] cod Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 4 ++-- Sources/NextcloudKit/NKMonitor.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 41995b2a..11675e60 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -161,8 +161,8 @@ public final class NKLogFileManager { // Prepare the console line with emoji prefix and keyword substitution let emojiPrefix = emojiColored(message) let visualMessage = message - .replacingOccurrences(of: "[SUCCESS]", with: "đŸŸĸ") - .replacingOccurrences(of: "[ERROR]", with: "🔴") + .replacingOccurrences(of: "RESPONSE: SUCCESS", with: "đŸŸĸ") + .replacingOccurrences(of: "RESPONSE: ERROR", with: "🔴") let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emojiPrefix)\(visualMessage)" print(consoleLine) diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index d2dd5bc3..fa3d87bb 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -58,7 +58,7 @@ final class NKMonitor: EventMonitor, Sendable { if let method = request.request?.httpMethod, let url = request.request?.url?.absoluteString, let code = response.response?.statusCode { - let response = (200..<300).contains(code) ? "SUCCESS" : "ERROR" + let response = (200..<300).contains(code) ? "RESPONSE: SUCCESS" : "RESPONSE: ERROR" nkLog(network: "\(code) \(method) \(url) \(response)") } case .verbose: From c85387a8c2558e59285ef9160e3426c1903c05f5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 11:36:45 +0200 Subject: [PATCH 35/54] helper Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index b85cc425..e48c0acf 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -34,9 +34,9 @@ public func nkLog(network message: String) { /// Logs a custom tagged message at the specified level. /// - Parameters: -/// - tag: A custom uppercase tag, e.g. \"UPLOAD\", \"SYNC\", \"AUTH\". +/// - tag: A custom uppercase tag, e.g. \"PUSH\", \"SYNC\", \"AUTH\". +/// - typeTag: the type tag .info, .debug, .warning, .error, .success .. /// - message: The message to log. -/// - level: The minimum level required for the message to be recorded. @inlinable public func nkLog(tag: String, typeTag: NKLogTypeTag = .debug, message: String) { NKLogFileManager.shared.writeLog(tag: tag, typeTag: typeTag, message: message) From 1ac085a97d1f09cc4ece851b7a87fb99fb7923a0 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 11:39:22 +0200 Subject: [PATCH 36/54] cleaning Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 11675e60..02211cd2 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -48,7 +48,7 @@ public enum NKLogTypeTag: String { } /// A logger that writes log messages to a file in a subdirectory of the user's Documents folder, -/// rotates the log daily, and compresses old logs with GZip. +/// rotates the log daily /// Compatible with iOS 13.0+ and Swift 6. public final class NKLogFileManager { @@ -104,13 +104,6 @@ public final class NKLogFileManager { // MARK: - Public API - public func compressedLogs() -> [URL] { - guard let files = try? fileManager.contentsOfDirectory(at: logDirectory, includingPropertiesForKeys: nil) else { - return [] - } - return files.filter { $0.pathExtension == "gz" } - } - public func writeLog(debug message: String) { writeLog("[DEBUG] \(message)") } @@ -134,8 +127,8 @@ public final class NKLogFileManager { /// Writes a tagged log message with a specific log level. /// - Parameters: /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). + /// - typeTag: the type tag .info, .debug, .warning, .error, .success .. /// - message: The log message content. - /// - level: The minimum level required for this message to be written. public func writeLog(tag: String, typeTag: NKLogTypeTag, message: String) { guard !tag.isEmpty else { return } let emojiColored = emojiColored(typeTag.rawValue) From 2b380fec424583f1f6dfd95e6a28ce3f8d65ac18 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 11:41:58 +0200 Subject: [PATCH 37/54] cleaning Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index e48c0acf..e8f14955 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -32,7 +32,7 @@ public func nkLog(network message: String) { NKLogFileManager.shared.writeLog(network: message) } -/// Logs a custom tagged message at the specified level. +/// Logs a custom tagged message. /// - Parameters: /// - tag: A custom uppercase tag, e.g. \"PUSH\", \"SYNC\", \"AUTH\". /// - typeTag: the type tag .info, .debug, .warning, .error, .success .. From a3cd895c24701c70ca09137039e0ed78cfe4d10f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 13:27:10 +0200 Subject: [PATCH 38/54] fix Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 02211cd2..dca9d3f8 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -131,18 +131,20 @@ public final class NKLogFileManager { /// - message: The log message content. public func writeLog(tag: String, typeTag: NKLogTypeTag, message: String) { guard !tag.isEmpty else { return } - let emojiColored = emojiColored(typeTag.rawValue) - writeLog("\(emojiColored)[\(tag.uppercased())] \(message)") + let taggedMessage = "[\(tag.uppercased())] \(message)" + writeLog(taggedMessage, typeTag: typeTag) } - /// Writes a log message to both the console and the log file. + /// Writes a log message with an optional typeTag to determine console emoji. /// Emojis and keyword replacements (e.g. [SUCCESS] -> đŸŸĸ) are only applied to the console output. - /// The log file is plain and suitable for parsing. Rotation is handled before writing. + /// The file output remains clean (no emoji or substitutions). /// - /// - Parameter message: The log message to record. - public func writeLog(_ message: String?) { - guard logLevel != .disabled, let message = message else { return } + /// - Parameters: + /// - message: The log message to record. + /// - typeTag: Optional log type tag to determine console emoji (e.g. [INFO], [ERROR]). + public func writeLog(_ message: String, typeTag: NKLogTypeTag? = nil) { + guard logLevel != .disabled else { return } // Generate timestamps for file and console let fileTimestamp = Self.stableTimestampString() @@ -151,21 +153,21 @@ public final class NKLogFileManager { // Prepare the clean file line (without emojis or replacements) let fileLine = "\(fileTimestamp) \(message)\n" - // Prepare the console line with emoji prefix and keyword substitution - let emojiPrefix = emojiColored(message) + // Determine emoji only if a typeTag is provided + let emojiPrefix = typeTag.map { emojiColored($0.rawValue) } ?? "" + + // Apply keyword replacements (e.g. [SUCCESS] -> đŸŸĸ) only in console let visualMessage = message - .replacingOccurrences(of: "RESPONSE: SUCCESS", with: "đŸŸĸ") - .replacingOccurrences(of: "RESPONSE: ERROR", with: "🔴") + .replacingOccurrences(of: "[SUCCESS]", with: "đŸŸĸ") + .replacingOccurrences(of: "[ERROR]", with: "🔴") let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emojiPrefix)\(visualMessage)" print(consoleLine) - // Ensure log rotation is completed before writing to the file rotationQueue.sync { self.checkForRotation() } - // Write to the log file asynchronously logQueue.async { self.appendToLog(fileLine) } From 9469c8f83a6b31897c0b9519ec1a4a5bedbb7327 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 13:37:02 +0200 Subject: [PATCH 39/54] fix Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index dca9d3f8..dab7fee0 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -143,25 +143,25 @@ public final class NKLogFileManager { /// - Parameters: /// - message: The log message to record. /// - typeTag: Optional log type tag to determine console emoji (e.g. [INFO], [ERROR]). - public func writeLog(_ message: String, typeTag: NKLogTypeTag? = nil) { - guard logLevel != .disabled else { return } + public func writeLog(_ message: String?, typeTag: NKLogTypeTag? = nil) { + guard logLevel != .disabled, let message = message else { return } - // Generate timestamps for file and console let fileTimestamp = Self.stableTimestampString() let consoleTimestamp = Self.localizedTimestampString() - - // Prepare the clean file line (without emojis or replacements) let fileLine = "\(fileTimestamp) \(message)\n" - // Determine emoji only if a typeTag is provided - let emojiPrefix = typeTag.map { emojiColored($0.rawValue) } ?? "" + // First emoji based on typeTag (e.g. [ERROR], [DEBUG], etc.) + let emojiFromTag = typeTag.map { emojiColored($0.rawValue) } ?? "" + + // Second emoji based on content of message (e.g. [SUCCESS] or [ERROR] keywords) + let emojiFromMessage = emojiColored(message) - // Apply keyword replacements (e.g. [SUCCESS] -> đŸŸĸ) only in console + // Build visual message with replacements let visualMessage = message .replacingOccurrences(of: "[SUCCESS]", with: "đŸŸĸ") .replacingOccurrences(of: "[ERROR]", with: "🔴") - let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emojiPrefix)\(visualMessage)" + let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emojiFromTag)\(emojiFromMessage)\(visualMessage)" print(consoleLine) rotationQueue.sync { From 0187d45453272b00a87db627547db17b7bc9cabe Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 13:42:35 +0200 Subject: [PATCH 40/54] cleaning Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index dab7fee0..25d185d6 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -150,18 +150,16 @@ public final class NKLogFileManager { let consoleTimestamp = Self.localizedTimestampString() let fileLine = "\(fileTimestamp) \(message)\n" - // First emoji based on typeTag (e.g. [ERROR], [DEBUG], etc.) - let emojiFromTag = typeTag.map { emojiColored($0.rawValue) } ?? "" + // Determine which emoji to display in console + let emoji = typeTag.map { emojiColored($0.rawValue) } ?? emojiColored(message) - // Second emoji based on content of message (e.g. [SUCCESS] or [ERROR] keywords) - let emojiFromMessage = emojiColored(message) - - // Build visual message with replacements + // Visual message with inline replacements let visualMessage = message .replacingOccurrences(of: "[SUCCESS]", with: "đŸŸĸ") .replacingOccurrences(of: "[ERROR]", with: "🔴") - let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emojiFromTag)\(emojiFromMessage)\(visualMessage)" + // Build the console line with emoji + let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emoji)\(visualMessage)" print(consoleLine) rotationQueue.sync { From ef2b1ac1ea2dec3604969a151ee48a88bc404590 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 13:49:08 +0200 Subject: [PATCH 41/54] improved Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 25d185d6..78adb27e 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -155,8 +155,8 @@ public final class NKLogFileManager { // Visual message with inline replacements let visualMessage = message - .replacingOccurrences(of: "[SUCCESS]", with: "đŸŸĸ") - .replacingOccurrences(of: "[ERROR]", with: "🔴") + .replacingOccurrences(of: "RESPONSE: SUCCESS", with: "đŸŸĸ") + .replacingOccurrences(of: "RESPONSE: ERROR", with: "🔴") // Build the console line with emoji let consoleLine = "[NKLOG] [\(consoleTimestamp)] \(emoji)\(visualMessage)" From 443fe92d00a13a16060e4940759389e3a474d3ea Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 14:02:17 +0200 Subject: [PATCH 42/54] rename Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 4 ++-- Sources/NextcloudKit/Log/NKLogFileManager.swift | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index e8f14955..6a96b740 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -38,6 +38,6 @@ public func nkLog(network message: String) { /// - typeTag: the type tag .info, .debug, .warning, .error, .success .. /// - message: The message to log. @inlinable -public func nkLog(tag: String, typeTag: NKLogTypeTag = .debug, message: String) { - NKLogFileManager.shared.writeLog(tag: tag, typeTag: typeTag, message: message) +public func nkLog(tag: String, emonji: NKLogTagEmoji = .debug, message: String) { + NKLogFileManager.shared.writeLog(tag: tag, emonji: emonji, message: message) } diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 78adb27e..c4da2b2e 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -38,8 +38,8 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { } } -/// Type for writes a tagged log message -public enum NKLogTypeTag: String { +/// Type for writes a emonji in writeLog(tag: ...) +public enum NKLogTagEmoji: String { case debug = "[DEBUG]" case info = "[INFO]" case warning = "[WARNING]" @@ -129,11 +129,11 @@ public final class NKLogFileManager { /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). /// - typeTag: the type tag .info, .debug, .warning, .error, .success .. /// - message: The log message content. - public func writeLog(tag: String, typeTag: NKLogTypeTag, message: String) { + public func writeLog(tag: String, emonji: NKLogTagEmoji, message: String) { guard !tag.isEmpty else { return } let taggedMessage = "[\(tag.uppercased())] \(message)" - writeLog(taggedMessage, typeTag: typeTag) + writeLog(taggedMessage, emonji: emonji) } /// Writes a log message with an optional typeTag to determine console emoji. @@ -143,7 +143,7 @@ public final class NKLogFileManager { /// - Parameters: /// - message: The log message to record. /// - typeTag: Optional log type tag to determine console emoji (e.g. [INFO], [ERROR]). - public func writeLog(_ message: String?, typeTag: NKLogTypeTag? = nil) { + public func writeLog(_ message: String?, emonji: NKLogTagEmoji? = nil) { guard logLevel != .disabled, let message = message else { return } let fileTimestamp = Self.stableTimestampString() @@ -151,7 +151,7 @@ public final class NKLogFileManager { let fileLine = "\(fileTimestamp) \(message)\n" // Determine which emoji to display in console - let emoji = typeTag.map { emojiColored($0.rawValue) } ?? emojiColored(message) + let emoji = emonji.map { emojiColored($0.rawValue) } ?? emojiColored(message) // Visual message with inline replacements let visualMessage = message From 44dc0b78fee32a31fb35a7e3b65fe9d53e0d91df Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 14:06:41 +0200 Subject: [PATCH 43/54] cleaning Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index c4da2b2e..59c5973e 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -40,11 +40,12 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { /// Type for writes a emonji in writeLog(tag: ...) public enum NKLogTagEmoji: String { - case debug = "[DEBUG]" - case info = "[INFO]" - case warning = "[WARNING]" case error = "[ERROR]" case success = "[SUCCESS]" + case warning = "[WARNING]" + case info = "[INFO]" + case debug = "[DEBUG]" + case network = "[NETWORK]" } /// A logger that writes log messages to a file in a subdirectory of the user's Documents folder, From 18be35c105cb39206f45e5db8e510dd32fb5a1d8 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 9 Jun 2025 14:53:20 +0200 Subject: [PATCH 44/54] added [START] [STOP] Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 10 ++++++++++ Sources/NextcloudKit/Log/NKLogFileManager.swift | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 6a96b740..0eb44c69 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -32,6 +32,16 @@ public func nkLog(network message: String) { NKLogFileManager.shared.writeLog(network: message) } +@inlinable +public func nkLog(start message: String) { + NKLogFileManager.shared.writeLog(start: message) +} + +@inlinable +public func nkLog(stop message: String) { + NKLogFileManager.shared.writeLog(stop: message) +} + /// Logs a custom tagged message. /// - Parameters: /// - tag: A custom uppercase tag, e.g. \"PUSH\", \"SYNC\", \"AUTH\". diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 59c5973e..93f82221 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -46,6 +46,8 @@ public enum NKLogTagEmoji: String { case info = "[INFO]" case debug = "[DEBUG]" case network = "[NETWORK]" + case start = "[START]" + case stop = "[STOP]" } /// A logger that writes log messages to a file in a subdirectory of the user's Documents folder, @@ -125,6 +127,14 @@ public final class NKLogFileManager { writeLog("[NETWORK] \(message)") } + public func writeLog(start message: String) { + writeLog("[START] \(message)") + } + + public func writeLog(stop message: String) { + writeLog("[STOP] \(message)") + } + /// Writes a tagged log message with a specific log level. /// - Parameters: /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). @@ -185,6 +195,10 @@ public final class NKLogFileManager { return "âšĒī¸ " } else if message.contains("[NETWORK]") { return "🌐 " + } else if message.contains("[START]") { + return "🚀 " + } else if message.contains("[STOP]") { + return "âšī¸ " } else { return "" } From d7eb70c468c66a0f0b2bf331ad811f5e3a67faa7 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 10 Jun 2025 11:02:00 +0200 Subject: [PATCH 45/54] rename Trace to Compact Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 4 ++-- Sources/NextcloudKit/NKMonitor.swift | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 93f82221..9fd25c46 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -11,7 +11,7 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { case disabled = 0 /// Logs basic request lifecycle for developers (request started, response result). - case trace = 1 + case compact = 1 /// Logs important info such as result content, errors. case normal = 2 @@ -26,7 +26,7 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { public var displayText: String { switch self { case .disabled: return NSLocalizedString("_disabled_", comment: "") - case .trace: return NSLocalizedString("_trace_", comment: "") + case .compact: return NSLocalizedString("_compact_", comment: "") case .normal: return NSLocalizedString("_normal_", comment: "") case .verbose: return NSLocalizedString("_verbose_", comment: "") } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index fa3d87bb..d4e5e0c4 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -54,12 +54,17 @@ final class NKMonitor: EventMonitor, Sendable { } else { nkLog(info: "Network response result: " + responseResultString) } - case .trace: + case .compact: if let method = request.request?.httpMethod, let url = request.request?.url?.absoluteString, let code = response.response?.statusCode { - let response = (200..<300).contains(code) ? "RESPONSE: SUCCESS" : "RESPONSE: ERROR" - nkLog(network: "\(code) \(method) \(url) \(response)") + // Determine response status string + let responseStatus = (200..<300).contains(code) ? "RESPONSE: SUCCESS" : "RESPONSE: ERROR" + + // Extract error code if any + let errorCode = response.error.map { " (\($0._code))" } ?? "" + + nkLog(network: "\(code) \(method) \(url) \(responseStatus)\(errorCode)") } case .verbose: nkLog(debug: "Network response result: \(date) " + responseDebugDescription) From 5b7dd6373814ac93fa6bde7311e413346e510880 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 10 Jun 2025 16:43:48 +0200 Subject: [PATCH 46/54] added success Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 5 +++++ Sources/NextcloudKit/Log/NKLogFileManager.swift | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 0eb44c69..1f33d263 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -27,6 +27,11 @@ public func nkLog(error message: String) { NKLogFileManager.shared.writeLog(error: message) } +@inlinable +public func nkLog(success message: String) { + NKLogFileManager.shared.writeLog(success: message) +} + @inlinable public func nkLog(network message: String) { NKLogFileManager.shared.writeLog(network: message) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 9fd25c46..3e24840f 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -123,6 +123,10 @@ public final class NKLogFileManager { writeLog("[ERROR] \(message)") } + public func writeLog(success message: String) { + writeLog("[SUCCESS] \(message)") + } + public func writeLog(network message: String) { writeLog("[NETWORK] \(message)") } From 30d4c472493cc06d03dc84ca39f63c266a89a383 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 11 Jun 2025 10:51:08 +0200 Subject: [PATCH 47/54] improvements Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NKMonitor.swift | 87 +++++++++++++++------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index d4e5e0c4..1f2ed5ce 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -14,63 +14,68 @@ final class NKMonitor: EventMonitor, Sendable { } func requestDidResume(_ request: Request) { - switch NKLogFileManager.shared.logLevel { - case .normal: - // General-purpose log: full Request description - nkLog(info: "Request started: \(request)") - case .verbose: - // Full dump: headers + body - let headers = request.request?.allHTTPHeaderFields?.description ?? "None" - let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" - nkLog(debug: "Request started: \(request)") - nkLog(debug: "Headers: \(headers)") - nkLog(debug: "Body: \(body)") - default: - break + DispatchQueue.global(qos: .utility).async { + switch NKLogFileManager.shared.logLevel { + case .normal: + // General-purpose log: full Request description + nkLog(info: "Request started: \(request)") + case .verbose: + // Full dump: headers + body + let headers = request.request?.allHTTPHeaderFields?.description ?? "None" + let body = request.request?.httpBody.flatMap { String(data: $0, encoding: .utf8) } ?? "None" + + nkLog(debug: "Request started: \(request)") + nkLog(debug: "Headers: \(headers)") + nkLog(debug: "Body: \(body)") + default: + break + } } } func request(_ request: DataRequest, didParseResponse response: AFDataResponse) { nkCommonInstance.delegate?.request(request, didParseResponse: response) + // Check for header and account error code tracking if let statusCode = response.response?.statusCode, let headerCheckInterceptor = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerCheckInterceptor], headerCheckInterceptor.lowercased() == "true", let account = request.request?.allHTTPHeaderFields?[nkCommonInstance.headerAccount] { nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode) } - guard let date = self.nkCommonInstance.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") else { - return - } - let responseResultString = String("\(response.result)") - let responseDebugDescription = String("\(response.debugDescription)") - let responseAllHeaderFields = String("\(String(describing: response.response?.allHeaderFields))") - switch NKLogFileManager.shared.logLevel { - case .normal: - if let request = response.request { - let requestString = "\(request)" - nkLog(info: "Network response request: " + requestString + ", result: " + responseResultString) - } else { - nkLog(info: "Network response result: " + responseResultString) - } - case .compact: - if let method = request.request?.httpMethod, - let url = request.request?.url?.absoluteString, - let code = response.response?.statusCode { - // Determine response status string - let responseStatus = (200..<300).contains(code) ? "RESPONSE: SUCCESS" : "RESPONSE: ERROR" + let date = nkCommonInstance.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") ?? "unknown" + let resultString = String(describing: response.result) + + DispatchQueue.global(qos: .utility).async { + switch NKLogFileManager.shared.logLevel { + case .normal: + if let request = response.request { + nkLog(info: "Network response request: \(request), result: \(resultString)") + } else { + nkLog(info: "Network response result: \(resultString)") + } + + case .compact: + if let method = request.request?.httpMethod, + let url = request.request?.url?.absoluteString, + let code = response.response?.statusCode { + + let responseStatus = (200..<300).contains(code) ? "RESPONSE: SUCCESS" : "RESPONSE: ERROR" + let errorCode = response.error.map { " (\($0._code))" } ?? "" + nkLog(network: "\(code) \(method) \(url) \(responseStatus)\(errorCode)") + } + + case .verbose: + let debugDesc = String(describing: response) + let headerFields = String(describing: response.response?.allHeaderFields ?? [:]) - // Extract error code if any - let errorCode = response.error.map { " (\($0._code))" } ?? "" + nkLog(debug: "Network response result: \(date) " + debugDesc) + nkLog(debug: "Network response all headers: \(date) " + headerFields) - nkLog(network: "\(code) \(method) \(url) \(responseStatus)\(errorCode)") + default: + break } - case .verbose: - nkLog(debug: "Network response result: \(date) " + responseDebugDescription) - nkLog(debug: "Network response all headers: \(date) " + responseAllHeaderFields) - default: - break } } } From c5f742840d2b2b25ca0228d8ba595237bac9f3a7 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 11 Jun 2025 14:58:09 +0200 Subject: [PATCH 48/54] remove (code) Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NKMonitor.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 1f2ed5ce..1258558f 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -62,8 +62,7 @@ final class NKMonitor: EventMonitor, Sendable { let code = response.response?.statusCode { let responseStatus = (200..<300).contains(code) ? "RESPONSE: SUCCESS" : "RESPONSE: ERROR" - let errorCode = response.error.map { " (\($0._code))" } ?? "" - nkLog(network: "\(code) \(method) \(url) \(responseStatus)\(errorCode)") + nkLog(network: "\(code) \(method) \(url) \(responseStatus)") } case .verbose: From 733563290bd965357a4eaf8578a80d1c2a807a28 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 11 Jun 2025 16:46:53 +0200 Subject: [PATCH 49/54] code improved Signed-off-by: Marino Faggiana --- .../Extensions/Date+Extension.swift | 11 +++++++++++ .../Extensions/String+Extension.swift | 4 ++++ Sources/NextcloudKit/Log/NKLog.swift | 6 +++--- Sources/NextcloudKit/NKCommon.swift | 18 ------------------ Sources/NextcloudKit/NKDataFileXML.swift | 9 ++++++--- Sources/NextcloudKit/NKMonitor.swift | 7 ++++--- Sources/NextcloudKit/NextcloudKit+API.swift | 14 ++++++-------- .../NextcloudKit/NextcloudKit+Download.swift | 4 ++-- Sources/NextcloudKit/NextcloudKit+Share.swift | 2 +- Sources/NextcloudKit/NextcloudKit+Upload.swift | 4 ++-- Sources/NextcloudKit/NextcloudKit+WebDAV.swift | 6 +++--- .../NextcloudKit/NextcloudKitBackground.swift | 6 +++--- 12 files changed, 45 insertions(+), 46 deletions(-) create mode 100644 Sources/NextcloudKit/Extensions/Date+Extension.swift diff --git a/Sources/NextcloudKit/Extensions/Date+Extension.swift b/Sources/NextcloudKit/Extensions/Date+Extension.swift new file mode 100644 index 00000000..ba39dcaa --- /dev/null +++ b/Sources/NextcloudKit/Extensions/Date+Extension.swift @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +extension Date { + func formatted(using format: String) -> String { + NKLogFileManager.shared.convertDate(self, format: format) + } +} diff --git a/Sources/NextcloudKit/Extensions/String+Extension.swift b/Sources/NextcloudKit/Extensions/String+Extension.swift index ebfcde33..256d782f 100644 --- a/Sources/NextcloudKit/Extensions/String+Extension.swift +++ b/Sources/NextcloudKit/Extensions/String+Extension.swift @@ -28,4 +28,8 @@ extension String { public var fileExtension: String { return String(NSString(string: self).pathExtension) } + + func parsedDate(using format: String) -> Date? { + NKLogFileManager.shared.convertDate(self, format: format) + } } diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 1f33d263..328f1c75 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -50,9 +50,9 @@ public func nkLog(stop message: String) { /// Logs a custom tagged message. /// - Parameters: /// - tag: A custom uppercase tag, e.g. \"PUSH\", \"SYNC\", \"AUTH\". -/// - typeTag: the type tag .info, .debug, .warning, .error, .success .. +/// - emoji: the type tag .info, .debug, .warning, .error, .success .. /// - message: The message to log. @inlinable -public func nkLog(tag: String, emonji: NKLogTagEmoji = .debug, message: String) { - NKLogFileManager.shared.writeLog(tag: tag, emonji: emonji, message: message) +public func nkLog(tag: String, emoji: NKLogTagEmoji = .debug, message: String) { + NKLogFileManager.shared.writeLog(tag: tag, emoji: emoji, message: message) } diff --git a/Sources/NextcloudKit/NKCommon.swift b/Sources/NextcloudKit/NKCommon.swift index eb2ffa4c..a2a56df4 100644 --- a/Sources/NextcloudKit/NKCommon.swift +++ b/Sources/NextcloudKit/NKCommon.swift @@ -509,24 +509,6 @@ public struct NKCommon: Sendable { return serverUrl.asUrl } - public func convertDate(_ dateString: String, format: String) -> Date? { - if dateString.isEmpty { return nil } - let dateFormatter = DateFormatter() - - dateFormatter.locale = Locale(identifier: "en_US_POSIX") - dateFormatter.dateFormat = format - guard let date = dateFormatter.date(from: dateString) else { return nil } - return date - } - - func convertDate(_ date: Date, format: String) -> String? { - let dateFormatter = DateFormatter() - - dateFormatter.locale = Locale(identifier: "en_US_POSIX") - dateFormatter.dateFormat = format - return dateFormatter.string(from: date) - } - func findHeader(_ header: String, allHeaderFields: [AnyHashable: Any]?) -> String? { guard let allHeaderFields = allHeaderFields else { return nil } let keyValues = allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) } diff --git a/Sources/NextcloudKit/NKDataFileXML.swift b/Sources/NextcloudKit/NKDataFileXML.swift index bafb99cd..d079d50f 100644 --- a/Sources/NextcloudKit/NKDataFileXML.swift +++ b/Sources/NextcloudKit/NKDataFileXML.swift @@ -308,7 +308,8 @@ public class NKDataFileXML: NSObject { let propstat = element["d:propstat"][0] - if let getlastmodified = propstat["d:prop", "d:getlastmodified"].text, let date = self.nkCommonInstance.convertDate(getlastmodified, format: "EEE, dd MMM y HH:mm:ss zzz") { + if let getlastmodified = propstat["d:prop", "d:getlastmodified"].text, + let date = getlastmodified.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") { file.date = date } @@ -600,7 +601,8 @@ public class NKDataFileXML: NSObject { let propstat = element["d:propstat"][0] - if let getlastmodified = propstat["d:prop", "d:getlastmodified"].text, let date = self.nkCommonInstance.convertDate(getlastmodified, format: "EEE, dd MMM y HH:mm:ss zzz") { + if let getlastmodified = propstat["d:prop", "d:getlastmodified"].text, + let date = getlastmodified.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") { file.date = date } @@ -678,7 +680,8 @@ public class NKDataFileXML: NSObject { item.actorType = value } - if let creationDateTime = element["d:propstat", "d:prop", "oc:creationDateTime"].text, let date = self.nkCommonInstance.convertDate(creationDateTime, format: "EEE, dd MMM y HH:mm:ss zzz") { + if let creationDateTime = element["d:propstat", "d:prop", "oc:creationDateTime"].text, + let date = creationDateTime.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") { item.creationDateTime = date } diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 1258558f..655dc56b 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -44,12 +44,11 @@ final class NKMonitor: EventMonitor, Sendable { nkCommonInstance.appendServerErrorAccount(account, errorCode: statusCode) } - let date = nkCommonInstance.convertDate(Date(), format: "yyyy-MM-dd' 'HH:mm:ss") ?? "unknown" - let resultString = String(describing: response.result) - DispatchQueue.global(qos: .utility).async { switch NKLogFileManager.shared.logLevel { case .normal: + let resultString = String(describing: response.result) + if let request = response.request { nkLog(info: "Network response request: \(request), result: \(resultString)") } else { @@ -68,6 +67,8 @@ final class NKMonitor: EventMonitor, Sendable { case .verbose: let debugDesc = String(describing: response) let headerFields = String(describing: response.response?.allHeaderFields ?? [:]) + let date = Date().formatted(using: "yyyy-MM-dd' 'HH:mm:ss") + nkLog(debug: "Network response result: \(date) " + debugDesc) nkLog(debug: "Network response all headers: \(date) " + headerFields) diff --git a/Sources/NextcloudKit/NextcloudKit+API.swift b/Sources/NextcloudKit/NextcloudKit+API.swift index 1225f764..d0864831 100644 --- a/Sources/NextcloudKit/NextcloudKit+API.swift +++ b/Sources/NextcloudKit/NextcloudKit+API.swift @@ -772,10 +772,9 @@ public extension NextcloudKit { activity.app = subJson["app"].stringValue activity.idActivity = subJson["activity_id"].intValue - if let datetime = subJson["datetime"].string { - if let date = self.nkCommonInstance.convertDate(datetime, format: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") { - activity.date = date - } + if let datetime = subJson["datetime"].string, + let date = datetime.parsedDate(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") { + activity.date = date } activity.icon = subJson["icon"].stringValue activity.link = subJson["link"].stringValue @@ -851,10 +850,9 @@ public extension NextcloudKit { } catch {} } notification.app = subJson["app"].stringValue - if let datetime = subJson["datetime"].string { - if let date = self.nkCommonInstance.convertDate(datetime, format: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") { - notification.date = date as Date - } + if let datetime = subJson["datetime"].string, + let date = datetime.parsedDate(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") { + notification.date = date } notification.icon = subJson["icon"].string notification.idNotification = subJson["notification_id"].intValue diff --git a/Sources/NextcloudKit/NextcloudKit+Download.swift b/Sources/NextcloudKit/NextcloudKit+Download.swift index 9574966b..07707052 100644 --- a/Sources/NextcloudKit/NextcloudKit+Download.swift +++ b/Sources/NextcloudKit/NextcloudKit+Download.swift @@ -59,8 +59,8 @@ public extension NextcloudKit { if etag != nil { etag = etag?.replacingOccurrences(of: "\"", with: "") } - if let dateString = self.nkCommonInstance.findHeader("Date", allHeaderFields: response.response?.allHeaderFields) { - date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + if let dateRaw = self.nkCommonInstance.findHeader("Date", allHeaderFields: response.response?.allHeaderFields) { + date = dateRaw.parsedDate(using: "yyyy-MM-dd HH:mm:ss") } options.queue.async { completionHandler(account, etag, date, length, response, nil, .success) } diff --git a/Sources/NextcloudKit/NextcloudKit+Share.swift b/Sources/NextcloudKit/NextcloudKit+Share.swift index dc9c874a..3774cbbd 100644 --- a/Sources/NextcloudKit/NextcloudKit+Share.swift +++ b/Sources/NextcloudKit/NextcloudKit+Share.swift @@ -435,7 +435,7 @@ public extension NextcloudKit { share.canEdit = json["can_edit"].boolValue share.displaynameFileOwner = json["displayname_file_owner"].stringValue share.displaynameOwner = json["displayname_owner"].stringValue - if let expiration = json["expiration"].string, let date = self.nkCommonInstance.convertDate(expiration, format: "YYYY-MM-dd HH:mm:ss") { + if let expiration = json["expiration"].string, let date = expiration.parsedDate(using: "YYYY-MM-dd HH:mm:ss") { share.expirationDate = date as NSDate } share.fileParent = json["file_parent"].intValue diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 5304debc..659d20bc 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -69,8 +69,8 @@ public extension NextcloudKit { if etag != nil { etag = etag?.replacingOccurrences(of: "\"", with: "") } - if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { - date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + if let dateRaw = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { + date = dateRaw.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") } if !uploadCompleted { diff --git a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift index 1dd8b8a9..45d0a349 100644 --- a/Sources/NextcloudKit/NextcloudKit+WebDAV.swift +++ b/Sources/NextcloudKit/NextcloudKit+WebDAV.swift @@ -33,7 +33,7 @@ public extension NextcloudKit { var date: Date? let ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: response.response?.allHeaderFields) { - date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + date = dateString.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") } let result = self.evaluateResponse(response) @@ -355,12 +355,12 @@ public extension NextcloudKit { var greaterDateString: String?, lessDateString: String? let href = "/files/" + nkSession.userId + path if let lessDate = lessDate as? Date { - lessDateString = self.nkCommonInstance.convertDate(lessDate, format: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") + lessDateString = lessDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") } else if let lessDate = lessDate as? Int { lessDateString = String(lessDate) } if let greaterDate = greaterDate as? Date { - greaterDateString = self.nkCommonInstance.convertDate(greaterDate, format: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") + greaterDateString = greaterDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") } else if let greaterDate = greaterDate as? Int { greaterDateString = String(greaterDate) } diff --git a/Sources/NextcloudKit/NextcloudKitBackground.swift b/Sources/NextcloudKit/NextcloudKitBackground.swift index dbcefc3c..32f07e9e 100644 --- a/Sources/NextcloudKit/NextcloudKitBackground.swift +++ b/Sources/NextcloudKit/NextcloudKitBackground.swift @@ -199,11 +199,11 @@ public final class NKBackground: NSObject, URLSessionTaskDelegate, URLSessionDel etag = self.nkCommonInstance.findHeader("etag", allHeaderFields: header) } if etag != nil { etag = etag?.replacingOccurrences(of: "\"", with: "") } - if let dateString = self.nkCommonInstance.findHeader("date", allHeaderFields: header) { - date = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + if let dateRaw = self.nkCommonInstance.findHeader("date", allHeaderFields: header) { + date = dateRaw.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") } if let dateString = header["Last-Modified"] as? String { - dateLastModified = self.nkCommonInstance.convertDate(dateString, format: "EEE, dd MMM y HH:mm:ss zzz") + dateLastModified = dateString.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz") } length = header["Content-Length"] as? Int64 ?? 0 } From 4474bb64910121d1db147dba3034f5414917ef53 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 11 Jun 2025 16:53:07 +0200 Subject: [PATCH 50/54] improvements & fix Signed-off-by: Marino Faggiana --- .../NextcloudKit/Log/NKLogFileManager.swift | 109 ++++++++++++++---- 1 file changed, 84 insertions(+), 25 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 3e24840f..a5416dfe 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -4,19 +4,19 @@ import Foundation -/// Defines the severity level of a log message. -/// Defines the level of log verbosity. +// Defines the severity level of a log message. +// Defines the level of log verbosity. public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { - /// Logging is disabled. + // Logging is disabled. case disabled = 0 - /// Logs basic request lifecycle for developers (request started, response result). + // Logs basic request lifecycle for developers (request started, response result). case compact = 1 - /// Logs important info such as result content, errors. + // Logs important info such as result content, errors. case normal = 2 - /// Logs detailed debug info like headers and bodies. + // Logs detailed debug info like headers and bodies. case verbose = 3 // Needed for Picker @@ -38,7 +38,7 @@ public enum NKLogLevel: Int, CaseIterable, Identifiable, Comparable { } } -/// Type for writes a emonji in writeLog(tag: ...) +/// Type for writes a emoji in writeLog(tag: ...) public enum NKLogTagEmoji: String { case error = "[ERROR]" case success = "[SUCCESS]" @@ -83,6 +83,10 @@ public final class NKLogFileManager { private let rotationQueue = DispatchQueue(label: "LogRotationQueue") private let fileManager = FileManager.default + /// Cache for dynamic format strings, populated at runtime. Thread-safe via serial queue. + private static var cachedDynamicFormatters: [String: DateFormatter] = [:] + private static let formatterAccessQueue = DispatchQueue(label: "com.yourapp.dateformatter.cache") + // MARK: - Initialization private init(logLevel: NKLogLevel = .normal) { @@ -99,8 +103,7 @@ public final class NKLogFileManager { /// Sets configuration parameters for the logger. /// - Parameters: - /// - logLevel: The log level. - /// + /// - logLevel: The NKLogLevel { disabled .. verbose } private func setConfiguration(logLevel: NKLogLevel) { self.logLevel = logLevel } @@ -142,13 +145,13 @@ public final class NKLogFileManager { /// Writes a tagged log message with a specific log level. /// - Parameters: /// - tag: A custom tag to classify the log message (e.g. "SYNC", "AUTH"). - /// - typeTag: the type tag .info, .debug, .warning, .error, .success .. + /// - emoji: .info, .debug, .warning, .error, .success .. /// - message: The log message content. - public func writeLog(tag: String, emonji: NKLogTagEmoji, message: String) { + public func writeLog(tag: String, emoji: NKLogTagEmoji, message: String) { guard !tag.isEmpty else { return } let taggedMessage = "[\(tag.uppercased())] \(message)" - writeLog(taggedMessage, emonji: emonji) + writeLog(taggedMessage, emoji: emoji) } /// Writes a log message with an optional typeTag to determine console emoji. @@ -157,8 +160,8 @@ public final class NKLogFileManager { /// /// - Parameters: /// - message: The log message to record. - /// - typeTag: Optional log type tag to determine console emoji (e.g. [INFO], [ERROR]). - public func writeLog(_ message: String?, emonji: NKLogTagEmoji? = nil) { + /// - emoji: Optional type to determine console emoji (e.g. [INFO], [ERROR]). + public func writeLog(_ message: String?, emoji: NKLogTagEmoji? = nil) { guard logLevel != .disabled, let message = message else { return } let fileTimestamp = Self.stableTimestampString() @@ -166,7 +169,7 @@ public final class NKLogFileManager { let fileLine = "\(fileTimestamp) \(message)\n" // Determine which emoji to display in console - let emoji = emonji.map { emojiColored($0.rawValue) } ?? emojiColored(message) + let emoji = emoji.map { emojiColored($0.rawValue) } ?? emojiColored(message) // Visual message with inline replacements let visualMessage = message @@ -253,33 +256,89 @@ public final class NKLogFileManager { } } - // MARK: - Date Helpers + // MARK: - Cached DateFormatters - private static func currentDateString() -> String { + /// Cached formatter for "yyyy-MM-dd". Uses current calendar, locale, and time zone. + private static let cachedCurrentDateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.calendar = Calendar.current formatter.locale = Locale.current formatter.timeZone = TimeZone.current formatter.dateFormat = "yyyy-MM-dd" - return formatter.string(from: Date()) - } + return formatter + }() - private static func stableTimestampString() -> String { + /// Cached formatter for "yyyy-MM-dd HH:mm:ss". Uses en_US_POSIX locale and Gregorian calendar for stable output. + private static let cachedStableTimestampFormatter: DateFormatter = { let formatter = DateFormatter() formatter.calendar = Calendar(identifier: .gregorian) formatter.locale = Locale(identifier: "en_US_POSIX") formatter.timeZone = TimeZone.current formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" - return formatter.string(from: Date()) - } + return formatter + }() - private static func localizedTimestampString() -> String { + /// Cached formatter using `.short` dateStyle and `.medium` timeStyle with current calendar and locale. + private static let cachedLocalizedTimestampFormatter: DateFormatter = { let formatter = DateFormatter() formatter.calendar = Calendar.current formatter.locale = Locale.current formatter.timeZone = TimeZone.current formatter.dateStyle = .short formatter.timeStyle = .medium - return formatter.string(from: Date()) + return formatter + }() + + /// Returns a cached `DateFormatter` instance for the given format string. + /// Formatters are created on-demand and reused to improve performance. + private static func cachedFormatter(for format: String) -> DateFormatter { + return formatterAccessQueue.sync { + if let formatter = cachedDynamicFormatters[format] { + return formatter + } + + let formatter = DateFormatter() + formatter.dateFormat = format + formatter.calendar = Calendar(identifier: .gregorian) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + cachedDynamicFormatters[format] = formatter + return formatter + } } -} + + /// Converts a `String` into a `Date` using a cached formatter for the specified format. + /// - Parameters: + /// - string: The date string to convert. + /// - format: The format pattern (e.g., "EEE, dd MMM y HH:mm:ss zzz"). + /// - Returns: A `Date` object if parsing succeeds; otherwise `nil`. + public func convertDate(_ string: String, format: String) -> Date? { + let formatter = Self.cachedFormatter(for: format) + return formatter.date(from: string) + } + + /// Converts a `Date` to a `String` using a cached formatter for the specified format. + /// - Parameters: + /// - date: The `Date` to format. + /// - format: The format string (e.g., "yyyy-MM-dd HH:mm:ss"). + /// - Returns: The formatted date string. + public func convertDate(_ date: Date, format: String) -> String { + let formatter = Self.cachedFormatter(for: format) + return formatter.string(from: date) + } + + /// Returns today's date string in "yyyy-MM-dd" format using a cached formatter. + private static func currentDateString() -> String { + return cachedCurrentDateFormatter.string(from: Date()) + } + + /// Returns a stable timestamp string in "yyyy-MM-dd HH:mm:ss" format using a cached formatter. + private static func stableTimestampString() -> String { + return cachedStableTimestampFormatter.string(from: Date()) + } + + /// Returns a localized timestamp string using short date and medium time styles. + private static func localizedTimestampString() -> String { + return cachedLocalizedTimestampFormatter.string(from: Date()) + } + } From 4f52260860d303a4c230f39df9f9ac89fbfab86f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Jun 2025 10:07:09 +0200 Subject: [PATCH 51/54] new async func() Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLog.swift | 4 +- .../NextcloudKit/Log/NKLogFileManager.swift | 2 +- Sources/NextcloudKit/NKMonitor.swift | 1 - .../NextcloudKit+TermsOfService.swift | 56 +++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLog.swift b/Sources/NextcloudKit/Log/NKLog.swift index 328f1c75..2dc8832c 100644 --- a/Sources/NextcloudKit/Log/NKLog.swift +++ b/Sources/NextcloudKit/Log/NKLog.swift @@ -4,8 +4,8 @@ import Foundation -/// Public logging helpers for apps using the NextcloudKit library. -/// These functions internally use `NKLogFileManager.shared`. +// Public logging helpers for apps using the NextcloudKit library. +// These functions internally use `NKLogFileManager.shared`. @inlinable public func nkLog(debug message: String) { diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index a5416dfe..61696dac 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -83,7 +83,7 @@ public final class NKLogFileManager { private let rotationQueue = DispatchQueue(label: "LogRotationQueue") private let fileManager = FileManager.default - /// Cache for dynamic format strings, populated at runtime. Thread-safe via serial queue. + // Cache for dynamic format strings, populated at runtime. Thread-safe via serial queue. private static var cachedDynamicFormatters: [String: DateFormatter] = [:] private static let formatterAccessQueue = DispatchQueue(label: "com.yourapp.dateformatter.cache") diff --git a/Sources/NextcloudKit/NKMonitor.swift b/Sources/NextcloudKit/NKMonitor.swift index 655dc56b..9b2b8388 100644 --- a/Sources/NextcloudKit/NKMonitor.swift +++ b/Sources/NextcloudKit/NKMonitor.swift @@ -69,7 +69,6 @@ final class NKMonitor: EventMonitor, Sendable { let headerFields = String(describing: response.response?.allHeaderFields ?? [:]) let date = Date().formatted(using: "yyyy-MM-dd' 'HH:mm:ss") - nkLog(debug: "Network response result: \(date) " + debugDesc) nkLog(debug: "Network response all headers: \(date) " + headerFields) diff --git a/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift b/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift index 9799ce98..aa70eedc 100644 --- a/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift +++ b/Sources/NextcloudKit/NextcloudKit+TermsOfService.swift @@ -7,6 +7,10 @@ import Alamofire import SwiftyJSON public extension NextcloudKit { + /// - Parameters: + /// - account: The account to query. + /// - options: Optional request options (defaults to standard). + /// - Returns: Tuple with NKError and optional NKTermsOfService. func getTermsOfService(account: String, options: NKRequestOptions = NKRequestOptions(), request: @escaping (DataRequest?) -> Void = { _ in }, @@ -43,6 +47,34 @@ public extension NextcloudKit { options.queue.async { request(tosRequest) } } + /// Async wrapper for `getTermsOfService(account:options:...)` + /// - Parameters: + /// - account: The account to query. + /// - options: Optional request options (defaults to standard). + /// - Returns: Tuple with NKError and optional NKTermsOfService. + func getTermsOfServiceAsync(account: String, + options: NKRequestOptions = NKRequestOptions(), + request: ((DataRequest?) -> Void)? = nil, + taskHandler: ((URLSessionTask) -> Void)? = nil + ) async -> (error: NKError, tos: NKTermsOfService?) { + await withCheckedContinuation { continuation in + self.getTermsOfService( + account: account, + options: options, + request: request ?? { _ in }, + taskHandler: taskHandler ?? { _ in } + ) { _, tos, _, error in + continuation.resume(returning: (error, tos)) + } + } + } + + /// - Parameters: + /// - termId: The ID of the ToS to sign. + /// - account: The user account. + /// - options: Optional request options. + /// - taskHandler: Optional URLSession task handler. + /// - Returns: NKError and AFDataResponse? func signTermsOfService(termId: String, account: String, options: NKRequestOptions = NKRequestOptions(), @@ -80,4 +112,28 @@ public extension NextcloudKit { } } } + + /// Async wrapper for `signTermsOfService` + /// - Parameters: + /// - termId: The ID of the ToS to sign. + /// - account: The user account. + /// - options: Optional request options. + /// - taskHandler: Optional URLSession task handler. + /// - Returns: NKError and AFDataResponse? + func signTermsOfServiceAsync(termId: String, + account: String, + options: NKRequestOptions = NKRequestOptions(), + taskHandler: ((URLSessionTask) -> Void)? = nil + ) async -> (error: NKError, response: AFDataResponse?) { + await withCheckedContinuation { continuation in + self.signTermsOfService( + termId: termId, + account: account, + options: options, + taskHandler: taskHandler ?? { _ in } + ) { _, responseData, error in + continuation.resume(returning: (error, responseData)) + } + } + } } From 242e662493a53f6c115cb67776682c243acf9095 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Jun 2025 11:13:55 +0200 Subject: [PATCH 52/54] added fileEmoji in configure Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index 61696dac..b8ae6728 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -64,8 +64,8 @@ public final class NKLogFileManager { /// - Parameters: /// - minLevel: The minimum log level to be recorded. - public static func configure(logLevel: NKLogLevel = .normal) { - shared.setConfiguration(logLevel: logLevel) + public static func configure(logLevel: NKLogLevel = .normal, fileEmoji: Bool = false) { + shared.setConfiguration(logLevel: logLevel, fileEmoji: fileEmoji) } /// Returns the file URL of the currently active log file. @@ -82,6 +82,7 @@ public final class NKLogFileManager { private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) private let rotationQueue = DispatchQueue(label: "LogRotationQueue") private let fileManager = FileManager.default + private var fileEmoji: Bool = false // Cache for dynamic format strings, populated at runtime. Thread-safe via serial queue. private static var cachedDynamicFormatters: [String: DateFormatter] = [:] @@ -89,8 +90,9 @@ public final class NKLogFileManager { // MARK: - Initialization - private init(logLevel: NKLogLevel = .normal) { + private init(logLevel: NKLogLevel = .normal, fileEmoji: Bool = false) { self.logLevel = logLevel + self.fileEmoji = fileEmoji let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let logsFolder = documents.appendingPathComponent("Logs", isDirectory: true) @@ -104,8 +106,9 @@ public final class NKLogFileManager { /// Sets configuration parameters for the logger. /// - Parameters: /// - logLevel: The NKLogLevel { disabled .. verbose } - private func setConfiguration(logLevel: NKLogLevel) { + private func setConfiguration(logLevel: NKLogLevel, fileEmoji: Bool = false) { self.logLevel = logLevel + self.fileEmoji = fileEmoji } // MARK: - Public API @@ -185,7 +188,11 @@ public final class NKLogFileManager { } logQueue.async { - self.appendToLog(fileLine) + if self.fileEmoji { + self.appendToLog(consoleLine) + } else { + self.appendToLog(fileLine) + } } } From c458b33a6b44711c1fcc20db87ac5a94f09dd86f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Jun 2025 11:17:42 +0200 Subject: [PATCH 53/54] cod Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/NextcloudKit+Logging.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index 2371b31f..f9117908 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -9,7 +9,7 @@ public extension NextcloudKit { } /// Configure the shared logger from NextcloudKit - static func configureLogger(logLevel: NKLogLevel = .normal) { - NKLogFileManager.configure(logLevel: logLevel) + static func configureLogger(logLevel: NKLogLevel = .normal, fileEmoji: Bool = false) { + NKLogFileManager.configure(logLevel: logLevel, fileEmoji: fileEmoji) } } From 1154d4f60f23884ac3de475d3db694954401a053 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Jun 2025 11:36:16 +0200 Subject: [PATCH 54/54] roll Signed-off-by: Marino Faggiana --- Sources/NextcloudKit/Log/NKLogFileManager.swift | 17 +++++------------ Sources/NextcloudKit/NextcloudKit+Logging.swift | 4 ++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Sources/NextcloudKit/Log/NKLogFileManager.swift b/Sources/NextcloudKit/Log/NKLogFileManager.swift index b8ae6728..61696dac 100644 --- a/Sources/NextcloudKit/Log/NKLogFileManager.swift +++ b/Sources/NextcloudKit/Log/NKLogFileManager.swift @@ -64,8 +64,8 @@ public final class NKLogFileManager { /// - Parameters: /// - minLevel: The minimum log level to be recorded. - public static func configure(logLevel: NKLogLevel = .normal, fileEmoji: Bool = false) { - shared.setConfiguration(logLevel: logLevel, fileEmoji: fileEmoji) + public static func configure(logLevel: NKLogLevel = .normal) { + shared.setConfiguration(logLevel: logLevel) } /// Returns the file URL of the currently active log file. @@ -82,7 +82,6 @@ public final class NKLogFileManager { private let logQueue = DispatchQueue(label: "LogWriterQueue", attributes: .concurrent) private let rotationQueue = DispatchQueue(label: "LogRotationQueue") private let fileManager = FileManager.default - private var fileEmoji: Bool = false // Cache for dynamic format strings, populated at runtime. Thread-safe via serial queue. private static var cachedDynamicFormatters: [String: DateFormatter] = [:] @@ -90,9 +89,8 @@ public final class NKLogFileManager { // MARK: - Initialization - private init(logLevel: NKLogLevel = .normal, fileEmoji: Bool = false) { + private init(logLevel: NKLogLevel = .normal) { self.logLevel = logLevel - self.fileEmoji = fileEmoji let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let logsFolder = documents.appendingPathComponent("Logs", isDirectory: true) @@ -106,9 +104,8 @@ public final class NKLogFileManager { /// Sets configuration parameters for the logger. /// - Parameters: /// - logLevel: The NKLogLevel { disabled .. verbose } - private func setConfiguration(logLevel: NKLogLevel, fileEmoji: Bool = false) { + private func setConfiguration(logLevel: NKLogLevel) { self.logLevel = logLevel - self.fileEmoji = fileEmoji } // MARK: - Public API @@ -188,11 +185,7 @@ public final class NKLogFileManager { } logQueue.async { - if self.fileEmoji { - self.appendToLog(consoleLine) - } else { - self.appendToLog(fileLine) - } + self.appendToLog(fileLine) } } diff --git a/Sources/NextcloudKit/NextcloudKit+Logging.swift b/Sources/NextcloudKit/NextcloudKit+Logging.swift index f9117908..2371b31f 100644 --- a/Sources/NextcloudKit/NextcloudKit+Logging.swift +++ b/Sources/NextcloudKit/NextcloudKit+Logging.swift @@ -9,7 +9,7 @@ public extension NextcloudKit { } /// Configure the shared logger from NextcloudKit - static func configureLogger(logLevel: NKLogLevel = .normal, fileEmoji: Bool = false) { - NKLogFileManager.configure(logLevel: logLevel, fileEmoji: fileEmoji) + static func configureLogger(logLevel: NKLogLevel = .normal) { + NKLogFileManager.configure(logLevel: logLevel) } }