BankingClient/ui/BankingiOSApp/BankingiOSApp/fints4k/UrlSessionWebClient.swift

130 lines
4.5 KiB
Swift

import Foundation
import BankingUiSwift
import MultiplatformUtils
class UrlSessionWebClient : Fints4kIWebClient {
func post(url: String, body: String, contentType: String, userAgent: String, callback: @escaping (Fints4kWebClientResponse) -> Void) {
let request = requestFor(url, "POST", body)
executeRequestAsync(request, callback)
}
func getAsync(_ url: String, callback: @escaping (Fints4kWebClientResponse) -> Void) {
let request = requestFor(url, "GET")
executeRequestAsync(request, callback)
}
func get(_ url: String) -> Fints4kWebClientResponse {
let request = requestFor(url, "GET")
return executeRequestSynchronous(request)
}
func getData(_ url: String) -> Data? {
let request = requestFor(url, "GET")
return executeDataRequestSynchronous(request)
}
func head(_ url: String) -> Fints4kWebClientResponse {
let request = requestFor(url, "HEAD")
return executeRequestSynchronous(request)
}
func requestFor(_ url: String, _ method: String, _ body: String? = nil) -> URLRequest {
guard let requestUrl = URL.encoded(url) else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = method
if let body = body {
request.httpBody = body.data(using: String.Encoding.utf8)
}
return request
}
func executeRequestAsync(_ request: URLRequest, _ callback: @escaping (Fints4kWebClientResponse) -> Void) {
let dataTask = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
// we have to dispatch response back to main thread as in Kotlin/Native objects can only be changed on one thread -> do all logic on main thread only network access in backbackground thread
DispatchQueue.main.async {
var webClientResponse = Fints4kWebClientResponse(successful: false, responseCode: -1, error: KotlinException(message: error?.localizedDescription), body: nil)
if let data = data, let httpResponse = response as? HTTPURLResponse {
webClientResponse = Fints4kWebClientResponse(successful: true, responseCode: Int32(httpResponse.statusCode), error: nil, body: String(data: data, encoding: .ascii))
}
callback(webClientResponse)
}
}
dataTask.resume()
}
func executeRequestSynchronous(_ request: URLRequest) -> Fints4kWebClientResponse {
var data: Data?, urlResponse: URLResponse?, error: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = URLSession.shared.dataTask(with: request) {
data = $0
urlResponse = $1
error = $2
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return mapResponse(data, urlResponse, error)
}
private func mapResponse(_ data: Data?, _ response: URLResponse?, _ error: Error?) -> Fints4kWebClientResponse {
let mappedError = error == nil ? nil : KotlinException(message: error?.localizedDescription)
if let httpResponse = response as? HTTPURLResponse {
let statusCode = Int32(httpResponse.statusCode)
let isSuccessful = mappedError == nil
&& statusCode >= 200 && statusCode <= 299
if let data = data {
return Fints4kWebClientResponse(successful: isSuccessful, responseCode: statusCode, error: mappedError, body: String(data: data, encoding: .ascii))
}
else {
return Fints4kWebClientResponse(successful: isSuccessful, responseCode: statusCode, error: mappedError, body: nil)
}
}
else {
return Fints4kWebClientResponse(successful: false, responseCode: -1, error: mappedError, body: nil)
}
}
func executeDataRequestSynchronous(_ request: URLRequest) -> Data? {
var data: Data?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = URLSession.shared.dataTask(with: request) { receivedData, _, _ in
data = receivedData
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return data
}
}