127 lines
4.3 KiB
Swift
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)
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
}
|