Skip to content

Commit 22be754

Browse files
authored
Merge pull request #415 from appwrite/feat-resumable-upload-swift
Feat resumable upload swift
2 parents 43ae5db + 515844e commit 22be754

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

templates/swift/Sources/Client.swift.twig

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ open class Client {
2121
open var headers: [String: String] = [
2222
"content-type": "",
2323
"x-sdk-version": "{{spec.title | caseDash}}:{{ language.name | caseLower }}:{{ sdk.version }}"{% if spec.global.defaultHeaders | length > 0 %},{% endif %}
24+
2425
{% for key,header in spec.global.defaultHeaders %}
2526
"{{key}}": "{{header}}"{% if not loop.last %},{% endif %}
26-
{% endfor %}
2727

28+
{% endfor %}
2829
]
2930

3031
open var config: [String: String] = [:]
@@ -228,7 +229,7 @@ open class Client {
228229
headers: [String: String] = [:],
229230
params: [String: Any?] = [:],
230231
sink: ((ByteBuffer) -> Void)? = nil,
231-
convert: (([String: Any]) -> T)? = nil,
232+
converter: (([String: Any]) -> T)? = nil,
232233
completion: ((Result<T, {{ spec.title | caseUcfirst }}Error>) -> Void)? = nil
233234
) {
234235
let validParams = params.filter { $0.value != nil }
@@ -259,7 +260,7 @@ open class Client {
259260
request.addDomainCookies()
260261

261262
if "GET" == method {
262-
execute(request, convert: convert, completion: completion)
263+
execute(request, converter: converter, completion: completion)
263264
return
264265
}
265266

@@ -272,7 +273,7 @@ open class Client {
272273
return
273274
}
274275

275-
execute(request, withSink: sink, convert: convert, completion: completion)
276+
execute(request, withSink: sink, converter: converter, completion: completion)
276277
}
277278

278279
private func buildBody(
@@ -289,7 +290,7 @@ open class Client {
289290
private func execute<T>(
290291
_ request: HTTPClient.Request,
291292
withSink bufferSink: ((ByteBuffer) -> Void)? = nil,
292-
convert: (([String: Any]) -> T)? = nil,
293+
converter: (([String: Any]) -> T)? = nil,
293294
completion: ((Result<T, {{ spec.title | caseUcfirst}}Error>) -> Void)? = nil
294295
) {
295296
if bufferSink == nil {
@@ -341,7 +342,7 @@ open class Client {
341342
let dict = try! JSONSerialization
342343
.jsonObject(with: response.body!) as? [String: Any]
343344

344-
completion(.success(convert?(dict!) ?? dict! as! T))
345+
completion(.success(converter?(dict!) ?? dict! as! T))
345346
}
346347
default:
347348
var message = ""
@@ -384,7 +385,8 @@ open class Client {
384385
headers: inout [String: String],
385386
params: inout [String: Any?],
386387
paramName: String,
387-
convert: (([String: Any]) -> T)? = nil,
388+
idParamName: String? = nil,
389+
converter: (([String: Any]) -> T)? = nil,
388390
onProgress: ((UploadProgress) -> Void)? = nil,
389391
completion: ((Result<T, {{ spec.title | caseUcfirst }}Error>) -> Void)? = nil
390392
) {
@@ -397,20 +399,44 @@ open class Client {
397399
path: path,
398400
headers: headers,
399401
params: params,
400-
convert: convert,
402+
converter: converter,
401403
completion: completion
402404
)
403405
return
404406
}
405407

406-
var input = file.buffer
408+
let input = file.buffer
407409
var offset = 0
408410
var result = [String:Any]()
409411
let group = DispatchGroup()
410412

413+
if idParamName != nil && params[idParamName!] as! String != "unique()" {
414+
// Make a request to check if a file already exists
415+
group.enter()
416+
call(
417+
method: "GET",
418+
path: path + "/" + (params[idParamName!] as! String),
419+
headers: headers,
420+
params: [:],
421+
converter: { return $0 }
422+
) { response in
423+
switch response {
424+
case let .success(map):
425+
let chunksUploaded = map["chunksUploaded"] as! Int
426+
offset = min(size, (chunksUploaded * Client.chunkSize))
427+
group.leave()
428+
case let .failure(error):
429+
completion?(.failure(error))
430+
group.leave()
431+
return
432+
}
433+
}
434+
group.wait()
435+
}
436+
411437
while offset < size {
412-
let slice = input.readSlice(length: Client.chunkSize)
413-
?? input.readSlice(length: Int(size - offset))
438+
let slice = input.getSlice(at: offset, length: Client.chunkSize)
439+
?? input.getSlice(at: offset, length: Int(size - offset))
414440

415441
params[paramName] = File(
416442
name: file.name,
@@ -426,7 +452,7 @@ open class Client {
426452
path: path,
427453
headers: headers,
428454
params: params,
429-
convert: { return $0 }
455+
converter: { return $0 }
430456
) { response in
431457
switch response {
432458
case let .success(map):
@@ -451,7 +477,7 @@ open class Client {
451477
))
452478
}
453479

454-
completion?(.success(convert!(result)))
480+
completion?(.success(converter!(result)))
455481
}
456482

457483

templates/swift/Sources/Services/Service.swift.twig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,12 @@ open class {{ service.name | caseUcfirst }}: Service {
3737
completion: ((Result<{{ _self.resultType(spec, method) }}, {{ spec.title | caseUcfirst}}Error>) -> Void)? = nil
3838
) {
3939
{% if method.parameters.path %} var{% else %} let{% endif %} path: String = "{{ method.path }}"
40-
4140
{% for parameter in method.parameters.path %}
4241
path = path.replacingOccurrences(
4342
of: "{{ '{' }}{{ parameter.name | caseCamel }}{{ '}' }}",
4443
with: {% if method.parameters.path %}{{ parameter.name | caseCamel | escapeKeyword }}{% else %}""{% endif %}
4544

4645
)
47-
4846
{% endfor %}
4947
{% if method.parameters.query or method.parameters.body or method.parameters.formData or _self.methodNeedsSecurityParameters(method) %}
5048
{% if 'multipart/form-data' in method.consumes %}var{% else %}let{% endif %} params: [String: Any?] = [
@@ -66,7 +64,6 @@ open class {{ service.name | caseUcfirst }}: Service {
6664
{% if method.parameters.query or method.parameters.body or method.parameters.formData or _self.methodNeedsSecurityParameters(method) %}
6765
]
6866
{% endif %}
69-
7067
{% if method.type == 'webAuth' %}
7168
let query = "?\(client.parametersToQueryString(params: params))"
7269
let url = URL(string: client.endPoint + path + query)!
@@ -89,31 +86,31 @@ open class {{ service.name | caseUcfirst }}: Service {
8986
{% if 'multipart/form-data' in method.consumes %}var{% else %}let{% endif %} headers: [String: String] = [
9087
{{ method.headers|map((header, key) => " \"#{key}\": \"#{header}\"")|join(',\n')|raw }}
9188
]
92-
9389
{% if method.responseModel %}
94-
let convert: ([String: Any]) -> {{ _self.resultType(spec, method) }} = { dict in
90+
let converter: ([String: Any]) -> {{ _self.resultType(spec, method) }} = { dict in
9591
{% if method.responseModel == 'any' %}
9692
return dict
9793
{% else %}
9894
return {{ spec.title | caseUcfirst}}Models.{{method.responseModel | caseUcfirst}}.from(map: dict)
9995
{% endif %}
10096
}
101-
10297
{% endif %}
10398
{% if 'multipart/form-data' in method.consumes %}
99+
let idParamName: String? = {% if method.parameters.all | filter(p => p.isUploadID) | length > 0 %}{% for parameter in method.parameters.all | filter(parameter => parameter.isUploadID) %}"{{ parameter.name }}"{% endfor %}{% else %}nil{% endif %}
100+
104101
{% for parameter in method.parameters.all %}
105102
{% if parameter.type == 'file' %}
106103
let paramName = "{{ parameter.name }}"
107-
108104
{% endif %}
109105
{% endfor %}
110106
client.chunkedUpload(
111107
path: path,
112108
headers: &headers,
113109
params: &params,
114110
paramName: paramName,
111+
idParamName: idParamName,
115112
{% if method.responseModel %}
116-
convert: convert,
113+
converter: converter,
117114
{% endif %}
118115
onProgress: onProgress,
119116
completion: completion
@@ -125,7 +122,7 @@ open class {{ service.name | caseUcfirst }}: Service {
125122
headers: headers,
126123
params: params,
127124
{% if method.responseModel %}
128-
convert: convert,
125+
converter: converter,
129126
{% endif %}
130127
completion: completion
131128
)

0 commit comments

Comments
 (0)