Files
2022-04-12 07:02:02 +00:00

127 lines
4.3 KiB
Swift

//
// NetworkTask.swift
// Cyberlock
//
// Created by Jura on 8/21/19.
// Copyright © 2019 Omicronmedia. All rights reserved.
//
import Foundation
public typealias CancellationToken = String
internal typealias NetworkingTaskCompletionClosure = (_ token: CancellationToken, _ result: Result<Response, Error>) -> Void
public protocol Cancellable {
var token: CancellationToken { get }
func cancel()
}
final class NetworkTask: Cancellable {
private let request: URLRequest
private let completion: NetworkingTaskCompletionClosure
private var task: URLSessionDataTask?
init(request: URLRequest, token: String? = nil, completion: @escaping NetworkingTaskCompletionClosure) {
self.request = request
self.completion = completion
self.token = token ?? UUID().uuidString
}
func start(with behaviour: StubBehavior, sampleResponse: Data?) {
switch behaviour {
case .never: self.performRequest()
case .immediate: self.perform(with: sampleResponse, after: 0)
case let .delayed(seconds: seconds): self.perform(with: sampleResponse, after: seconds)
}
}
// MARK: - Cancellable
let token: CancellationToken
func cancel() {
self.task?.cancel()
self.task = nil
}
// MARK: -
// MARK: - Private
private func performRequest() {
let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 1
config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
config.urlCache = nil
let session = URLSession(configuration: config)
let task = session.dataTask(with: self.request) { [weak self] (data, response, error) in
guard let self = self else { return }
guard let task = self.task else {
self.completion(self.token, Result.failure(NetworkRouterError.cancelled))
return
}
task.cancel()
self.task = nil
let result = NetworkTask.convertResponseToResult(response as? HTTPURLResponse, data: data, error: error, request: self.request)
self.completion(self.token, result)
}
self.task = task
task.resume()
}
private func perform(with sampleData: Data?, after seconds: TimeInterval) {
let completionHandler = { [weak self] in
guard let self = self else { return }
let result = NetworkTask.convertResponseToResult(nil, data: sampleData, error: nil, request: self.request)
self.completion(self.token, result)
}
guard seconds > 0 else {
completionHandler()
return
}
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + seconds, execute: completionHandler)
}
private static func convertResponseToResult(_ response: HTTPURLResponse?, data: Data?, error: Error?, request: URLRequest) -> Result<Response, Error> {
let taskResponse = Response(statusCode: response?.statusCode ?? 200,
data: data ?? Data(),
response: response,
request: request)
return Result.success(taskResponse)
/*
switch (data, error) {
case (.some, .none):
return self.errorFromServerResponse(tossResponse)
>>- { self.fail(with: $0, response: tossResponse) }
?? .success(tossResponse)
case let (_, error?):
guard (error as NSError).domain != NSURLErrorDomain else {
return self.fail(with: error, response: tossResponse)
}
guard let errorFromResponse = self.errorFromServerResponse(tossResponse) else {
let generalError = NSError.tossSpecificError(with: (error as NSError).code,
response: tossResponse,
localizedDescription: (error as NSError).localizedDescription)
return self.fail(with: generalError, response: tossResponse)
}
return self.fail(with: errorFromResponse, response: tossResponse)
default:
let error = NSError.tossSpecificError(with: .unknown, response: tossResponse)
return self.fail(with: error, response: tossResponse)
}
*/
}
}