Skip to content

Commit

Permalink
feat(swift5): implement background upload
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibaultBee committed Nov 27, 2023
1 parent c58ac47 commit 2292f62
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions config/swift5-uploader.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ additionalProperties:
podHomepage: https://docs.api.video
podSocialMediaUrl: https://twitter.com/api_video
podLicense: "{ :type => 'MIT' }"
backgroundSupport: true
defaultChunkSize: 50 * 1024 * 1024
minChunkSize: 5 * 1024 * 1024
maxChunkSize: 128 * 1024 * 1024
Expand Down
1 change: 1 addition & 0 deletions config/swift5.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ additionalProperties:
podHomepage: https://docs.api.video
podSocialMediaUrl: https://twitter.com/api_video
podLicense: "{ :type => 'MIT' }"
backgroundSupport: true
defaultChunkSize: 50 * 1024 * 1024
minChunkSize: 5 * 1024 * 1024
maxChunkSize: 128 * 1024 * 1024
Expand Down
4 changes: 2 additions & 2 deletions templates/swift5/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ extension {{projectName}}API {

let localVariableHeaderParameters = APIHelper.rejectNilHeaders(localVariableNillableHeaders)

let localVariableRequestBuilder: RequestBuilder<{{{returnType}}}{{^returnType}}Void{{/returnType}}>.Type = {{projectName}}.requestBuilderFactory.{{#returnType}}getBuilder(){{/returnType}}{{^returnType}}getNonDecodableBuilder(){{/returnType}}
let localVariableRequestBuilder: RequestBuilder<{{{returnType}}}{{^returnType}}Void{{/returnType}}>.Type = {{projectName}}.requestBuilderFactory.{{#vendorExtensions.x-client-chunk-upload}}getBackgroundBuilder(){{/vendorExtensions.x-client-chunk-upload}}{{^vendorExtensions.x-client-chunk-upload}}{{#returnType}}getBuilder(){{/returnType}}{{^returnType}}getNonDecodableBuilder(){{/returnType}}{{/vendorExtensions.x-client-chunk-upload}}

return localVariableRequestBuilder.init(method: "{{httpMethod}}", URLString: (localVariableUrlComponents?.string ?? localVariableURLString), parameters: localVariableParameters, headers: localVariableHeaderParameters{{#vendorExtensions.x-client-chunk-upload}}, onProgressReady: onProgressReady{{/vendorExtensions.x-client-chunk-upload}})
}
Expand Down Expand Up @@ -620,7 +620,7 @@ extension {{projectName}}API {

let localVariableHeaderParameters = APIHelper.rejectNilHeaders(localVariableNillableHeaders)

let localVariableRequestBuilder: RequestBuilder<{{{returnType}}}{{^returnType}}Void{{/returnType}}>.Type = {{projectName}}.requestBuilderFactory.{{#returnType}}getBuilder(){{/returnType}}{{^returnType}}getNonDecodableBuilder(){{/returnType}}
let localVariableRequestBuilder: RequestBuilder<{{{returnType}}}{{^returnType}}Void{{/returnType}}>.Type = {{projectName}}.requestBuilderFactory.{{#vendorExtensions.x-client-chunk-upload}}getBackgroundBuilder(){{/vendorExtensions.x-client-chunk-upload}}{{^vendorExtensions.x-client-chunk-upload}}{{#returnType}}getBuilder(){{/returnType}}{{^returnType}}getNonDecodableBuilder(){{/returnType}}{{/vendorExtensions.x-client-chunk-upload}}

return localVariableRequestBuilder.init(method: "{{httpMethod}}", URLString: (localVariableUrlComponents?.string ?? localVariableURLString), parameters: localVariableParameters, headers: localVariableHeaderParameters, onProgressReady: onProgressReady)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ class URLSessionRequestBuilderFactory: RequestBuilderFactory {

func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
return URLSessionDecodableRequestBuilder<T>.self
}{{#backgroundSupport}}

func getBackgroundBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
return URLSessionDecodableBackgroundUploadRequestBuilder<T>.self
}
{{/backgroundSupport}}
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} typealias {{projectName}}ChallengeHandler = ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))
Expand Down Expand Up @@ -376,8 +381,61 @@ private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
}
}
}
}{{#backgroundSupport}}

private class BackgroundUploadTaskURLSession<T>: NSObject, URLSessionProtocol, URLSessionDelegate, URLSessionDataDelegate {
private let file: URL
private lazy var urlSession: URLSession = {
URLSession(configuration: .background(withIdentifier: ApiVideoClient.backgroundIdentifier), delegate: self, delegateQueue: nil)
}()
private var completion: ((Data?, URLResponse?, Error?) -> Void)? = nil

init(_ file: URL) {
self.file = file
}

func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
completion = completionHandler
return urlSession.uploadTask(with: request, fromFile: file)
}

func urlSession(_ session: URLSession, task: URLSessionTask, didBecomeInvalidWithError error: Error?) {
guard let error = error else {
return
}
completion?(nil, task.response, error)
}

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
completion?(data, dataTask.response, nil)
}

func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
sessionDelegate.urlSession(session, task: task, didReceive: challenge, completionHandler: completionHandler)
}
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionDecodableBackgroundUploadRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
private var completion: ((Result<Response<T>, ErrorResponse>) -> Void)? = nil
override open func createURLSession() -> URLSessionProtocol {
guard let parameters = parameters else { fatalError("No parameters found") }

// Find file URL
var file: URL? = nil
for (_, value) in parameters {
if let fileURL = value as? URL {
file = fileURL
break
}
}
guard let fileURL = file else {
fatalError("No file URL found")
}
return BackgroundUploadTaskURLSession<T>(fileURL)
}
}{{/backgroundSupport}}

private class SessionDelegate: NSObject, URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
Expand Down

0 comments on commit 2292f62

Please sign in to comment.