Skip to content

Commit 7e3dcff

Browse files
async
Signed-off-by: Marino Faggiana <marino@marinofaggiana.com>
1 parent 628f44b commit 7e3dcff

4 files changed

Lines changed: 618 additions & 14 deletions

File tree

Sources/NextcloudKit/NextcloudKit+Search.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,51 @@ public extension NextcloudKit {
197197

198198
return requestSearchProvider
199199
}
200+
201+
// Asynchronously performs a search request using the specified provider.
202+
//
203+
// Parameters:
204+
// - id: The identifier of the search provider to use.
205+
// - term: The search query string.
206+
// - limit: Optional limit for number of results.
207+
// - cursor: Optional pagination cursor.
208+
// - timeout: The timeout for the request.
209+
// - account: The Nextcloud account performing the request.
210+
// - options: Optional configuration options for the request.
211+
// - taskHandler: Callback to observe the created task.
212+
// Returns: A tuple containing the account, search result, response data, and error.
213+
func searchProviderAsync(_ id: String,
214+
term: String,
215+
limit: Int? = nil,
216+
cursor: Int? = nil,
217+
timeout: TimeInterval = 60,
218+
account: String,
219+
options: NKRequestOptions = NKRequestOptions(),
220+
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }
221+
) async -> (
222+
account: String,
223+
searchResult: NKSearchResult?,
224+
responseData: AFDataResponse<Data>?,
225+
error: NKError
226+
) {
227+
await withCheckedContinuation { continuation in
228+
_ = searchProvider(id,
229+
term: term,
230+
limit: limit,
231+
cursor: cursor,
232+
timeout: timeout,
233+
account: account,
234+
options: options,
235+
taskHandler: taskHandler) { account, result, responseData, error in
236+
continuation.resume(returning: (
237+
account: account,
238+
searchResult: result,
239+
responseData: responseData,
240+
error: error
241+
))
242+
}
243+
}
244+
}
200245
}
201246

202247
public class NKSearchResult: NSObject {

Sources/NextcloudKit/NextcloudKit+ShareDownloadLimit.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ public extension NextcloudKit {
1111
"ocs/v2.php/apps/files_downloadlimit/api/v1/\(token)/limit"
1212
}
1313

14+
// Retrieves the current download limit for a shared file based on its public share token.
15+
//
16+
// Parameters:
17+
// - account: The Nextcloud account identifier.
18+
// - token: The public share token associated with the file or folder.
19+
// - completion: A closure returning:
20+
// - NKDownloadLimit?: The current download limit information, or `nil` if not available.
21+
// - NKError: An object representing success or error during the request.
1422
func getDownloadLimit(account: String, token: String, completion: @escaping (NKDownloadLimit?, NKError) -> Void) {
1523
let endpoint = makeEndpoint(with: token)
1624
let options = NKRequestOptions()
@@ -76,6 +84,36 @@ public extension NextcloudKit {
7684
}
7785
}
7886

87+
// Retrieves the current download limit for a shared file using its public token.
88+
//
89+
// Parameters:
90+
// - account: The account associated with the Nextcloud session.
91+
// - token: The public share token used to identify the shared file.
92+
//
93+
// Returns: A tuple containing:
94+
// - downloadLimit: The current NKDownloadLimit object if available.
95+
// - error: The NKError representing success or failure of the request.
96+
func getDownloadLimitAsync(account: String, token: String) async -> (
97+
downloadLimit: NKDownloadLimit?,
98+
error: NKError
99+
) {
100+
await withCheckedContinuation { continuation in
101+
getDownloadLimit(account: account, token: token) { limit, error in
102+
continuation.resume(returning: (
103+
downloadLimit: limit,
104+
error: error
105+
))
106+
}
107+
}
108+
}
109+
110+
// Removes the download limit for a shared file using its public share token.
111+
//
112+
// Parameters:
113+
// - account: The Nextcloud account identifier.
114+
// - token: The public share token associated with the file or folder.
115+
// - completion: A closure returning:
116+
// - NKError: An object representing the success or failure of the request.
79117
func removeShareDownloadLimit(account: String, token: String, completion: @escaping (_ error: NKError) -> Void) {
80118
let endpoint = makeEndpoint(with: token)
81119
let options = NKRequestOptions()
@@ -108,6 +146,29 @@ public extension NextcloudKit {
108146
}
109147
}
110148

149+
// Asynchronously removes the download limit for a public shared file or folder.
150+
//
151+
// Parameters:
152+
// - account: The Nextcloud account used for the request.
153+
// - token: The public token representing the shared resource.
154+
//
155+
// Returns: An NKError that indicates the outcome of the operation.
156+
func removeShareDownloadLimitAsync(account: String, token: String) async -> NKError {
157+
await withCheckedContinuation { continuation in
158+
removeShareDownloadLimit(account: account, token: token) { error in
159+
continuation.resume(returning: error)
160+
}
161+
}
162+
}
163+
164+
// Sets a download limit for a public shared file or folder.
165+
//
166+
// Parameters:
167+
// - account: The Nextcloud account associated with the request.
168+
// - token: The public share token identifying the shared resource.
169+
// - limit: The new download limit to be set.
170+
// - completion: A closure returning:
171+
// - error: An NKError representing the success or failure of the operation.
111172
func setShareDownloadLimit(account: String, token: String, limit: Int, completion: @escaping (_ error: NKError) -> Void) {
112173
let endpoint = makeEndpoint(with: token)
113174
let options = NKRequestOptions()
@@ -145,4 +206,20 @@ public extension NextcloudKit {
145206
}
146207
}
147208
}
209+
210+
// Asynchronously sets a download limit for a public shared file or folder.
211+
//
212+
// Parameters:
213+
// - account: The Nextcloud account used for the request.
214+
// - token: The public share token of the resource.
215+
// - limit: The maximum number of downloads to allow.
216+
//
217+
// Returns: An NKError indicating whether the operation was successful.
218+
func setShareDownloadLimitAsync(account: String, token: String, limit: Int) async -> NKError {
219+
await withCheckedContinuation { continuation in
220+
setShareDownloadLimit(account: account, token: token, limit: limit) { error in
221+
continuation.resume(returning: error)
222+
}
223+
}
224+
}
148225
}

Sources/NextcloudKit/NextcloudKit+Upload.swift

Lines changed: 165 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ import Alamofire
77
import SwiftyJSON
88

99
public extension NextcloudKit {
10+
// Uploads a file to the Nextcloud server.
11+
//
12+
// Parameters:
13+
// - serverUrlFileName: The remote server URL or path where the file will be uploaded.
14+
// - fileNameLocalPath: The local file path to be uploaded.
15+
// - dateCreationFile: Optional creation date to include in headers (X-OC-CTime).
16+
// - dateModificationFile: Optional modification date to include in headers (X-OC-MTime).
17+
// - overwrite: If true, the remote file will be overwritten if it already exists.
18+
// - account: The account associated with the upload session.
19+
// - options: Optional configuration for the request (headers, queue, timeout, etc.).
20+
// - requestHandler: Called with the created UploadRequest.
21+
// - taskHandler: Called with the underlying URLSessionTask when it's created.
22+
// - progressHandler: Called periodically with upload progress.
23+
// - completionHandler: Called at the end of the upload with:
24+
// - account: The account used,
25+
// - ocId: The server-side file identifier,
26+
// - etag: The entity tag for versioning,
27+
// - date: The server date of the operation,
28+
// - size: The total uploaded size in bytes,
29+
// - headers: The response headers,
30+
// - nkError: The result status.
1031
func upload(serverUrlFileName: Any,
1132
fileNameLocalPath: String,
1233
dateCreationFile: Date? = nil,
@@ -88,17 +109,88 @@ public extension NextcloudKit {
88109
options.queue.async { requestHandler(request) }
89110
}
90111

91-
/// - Parameters:
92-
/// - directory: The local directory where is the file to be split
93-
/// - fileName: The name of the file to be splites
94-
/// - date: If exist the date of file
95-
/// - creationDate: If exist the creation date of file
96-
/// - serverUrl: The serverURL where the file will be deposited once reassembled
97-
/// - chunkFolder: The name of temp folder, usually NSUUID().uuidString
98-
/// - filesChunk: The struct it will contain all file names with the increment size still to be sent.
99-
/// Example filename: "3","4","5" .... size: 30000000, 40000000, 43000000
100-
/// - chunkSizeInMB: Size in MB of chunk
112+
// Asynchronously uploads a file to the Nextcloud server.
113+
//
114+
// - Parameters are the same as the synchronous version.
115+
//
116+
// - Returns: A tuple with:
117+
// - account: The account used for the upload.
118+
// - ocId: The remote file identifier returned by the server.
119+
// - etag: The file etag returned by the server.
120+
// - date: The server timestamp.
121+
// - size: The size of the uploaded file in bytes.
122+
// - headers: The raw HTTP response headers.
123+
// - error: The NKError result of the upload.
124+
func uploadAsync(serverUrlFileName: Any,
125+
fileNameLocalPath: String,
126+
dateCreationFile: Date? = nil,
127+
dateModificationFile: Date? = nil,
128+
overwrite: Bool = false,
129+
account: String,
130+
options: NKRequestOptions = NKRequestOptions(),
131+
requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in },
132+
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in },
133+
progressHandler: @escaping (_ progress: Progress) -> Void = { _ in }
134+
) async -> (
135+
account: String,
136+
ocId: String?,
137+
etag: String?,
138+
date: Date?,
139+
size: Int64,
140+
headers: [AnyHashable: Any]?,
141+
error: NKError
142+
) {
143+
await withCheckedContinuation { continuation in
144+
upload(serverUrlFileName: serverUrlFileName,
145+
fileNameLocalPath: fileNameLocalPath,
146+
dateCreationFile: dateCreationFile,
147+
dateModificationFile: dateModificationFile,
148+
overwrite: overwrite,
149+
account: account,
150+
options: options,
151+
requestHandler: requestHandler,
152+
taskHandler: taskHandler,
153+
progressHandler: progressHandler) { account, ocId, etag, date, size, headers, error in
154+
continuation.resume(returning: (
155+
account: account,
156+
ocId: ocId,
157+
etag: etag,
158+
date: date,
159+
size: size,
160+
headers: headers,
161+
error: error
162+
))
163+
}
164+
}
165+
}
101166

167+
// Uploads a file in multiple chunks to the Nextcloud server using TUS-like behavior.
168+
//
169+
// Parameters:
170+
// - directory: The local directory containing the original file.
171+
// - fileChunksOutputDirectory: Optional custom output directory for chunks (default is same as `directory`).
172+
// - fileName: Name of the original file to split and upload.
173+
// - destinationFileName: Optional custom filename to be used on the server.
174+
// - date: The modification date to be set on the uploaded file.
175+
// - creationDate: The creation date to be set on the uploaded file.
176+
// - serverUrl: The destination server path.
177+
// - chunkFolder: A temporary folder name (usually a UUID).
178+
// - filesChunk: List of chunk identifiers and their expected sizes.
179+
// - chunkSize: Size of each chunk in bytes.
180+
// - account: The Nextcloud account used for authentication.
181+
// - options: Request options (headers, queue, etc.).
182+
// - numChunks: Callback invoked with total number of chunks.
183+
// - counterChunk: Callback invoked with the index of the chunk being uploaded.
184+
// - start: Called when chunk upload begins, with the full chunk list.
185+
// - requestHandler: Handler to inspect the upload request.
186+
// - taskHandler: Handler to inspect the upload task.
187+
// - progressHandler: Progress callback with expected bytes, transferred bytes, and fraction completed.
188+
// - uploaded: Called each time a chunk is successfully uploaded.
189+
// - completion: Called when all chunks are uploaded and reassembled. Returns:
190+
// - account: The user account used.
191+
// - filesChunk: Remaining chunks (if any).
192+
// - file: The final `NKFile` metadata for the uploaded file.
193+
// - error: Upload result as `NKError`.
102194
func uploadChunk(directory: String,
103195
fileChunksOutputDirectory: String? = nil,
104196
fileName: String,
@@ -119,7 +211,6 @@ public extension NextcloudKit {
119211
progressHandler: @escaping (_ totalBytesExpected: Int64, _ totalBytes: Int64, _ fractionCompleted: Double) -> Void = { _, _, _ in },
120212
uploaded: @escaping (_ fileChunk: (fileName: String, size: Int64)) -> Void = { _ in },
121213
completion: @escaping (_ account: String, _ filesChunk: [(fileName: String, size: Int64)]?, _ file: NKFile?, _ error: NKError) -> Void) {
122-
123214
guard let nkSession = nkCommonInstance.nksessions.session(forAccount: account) else {
124215
return completion(account, nil, nil, .urlError)
125216
}
@@ -260,4 +351,67 @@ public extension NextcloudKit {
260351
}
261352
}
262353
}
354+
355+
// Asynchronously uploads a file in chunks and assembles it on the Nextcloud server.
356+
//
357+
// - Parameters: Same as the sync version.
358+
// - Returns: A tuple containing:
359+
// - account: The user account used.
360+
// - remainingChunks: Remaining chunks if any failed (or nil if success).
361+
// - file: The final file metadata object.
362+
// - error: Upload result as `NKError`.
363+
func uploadChunkAsync(directory: String,
364+
fileChunksOutputDirectory: String? = nil,
365+
fileName: String,
366+
destinationFileName: String? = nil,
367+
date: Date?,
368+
creationDate: Date?,
369+
serverUrl: String,
370+
chunkFolder: String,
371+
filesChunk: [(fileName: String, size: Int64)],
372+
chunkSize: Int,
373+
account: String,
374+
options: NKRequestOptions = NKRequestOptions(),
375+
numChunks: @escaping (_ num: Int) -> Void = { _ in },
376+
counterChunk: @escaping (_ counter: Int) -> Void = { _ in },
377+
start: @escaping (_ filesChunk: [(fileName: String, size: Int64)]) -> Void = { _ in },
378+
requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in },
379+
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in },
380+
progressHandler: @escaping (_ totalBytesExpected: Int64, _ totalBytes: Int64, _ fractionCompleted: Double) -> Void = { _, _, _ in },
381+
uploaded: @escaping (_ fileChunk: (fileName: String, size: Int64)) -> Void = { _ in }
382+
) async -> (
383+
account: String,
384+
remainingChunks: [(fileName: String, size: Int64)]?,
385+
file: NKFile?,
386+
error: NKError
387+
) {
388+
await withCheckedContinuation { continuation in
389+
uploadChunk(directory: directory,
390+
fileChunksOutputDirectory: fileChunksOutputDirectory,
391+
fileName: fileName,
392+
destinationFileName: destinationFileName,
393+
date: date,
394+
creationDate: creationDate,
395+
serverUrl: serverUrl,
396+
chunkFolder: chunkFolder,
397+
filesChunk: filesChunk,
398+
chunkSize: chunkSize,
399+
account: account,
400+
options: options,
401+
numChunks: numChunks,
402+
counterChunk: counterChunk,
403+
start: start,
404+
requestHandler: requestHandler,
405+
taskHandler: taskHandler,
406+
progressHandler: progressHandler,
407+
uploaded: uploaded) { account, remaining, file, error in
408+
continuation.resume(returning: (
409+
account: account,
410+
remainingChunks: remaining,
411+
file: file,
412+
error: error
413+
))
414+
}
415+
}
416+
}
263417
}

0 commit comments

Comments
 (0)