92 lines
2.0 KiB
Swift
92 lines
2.0 KiB
Swift
|
//
|
||
|
// API.swift
|
||
|
// NotificationService
|
||
|
//
|
||
|
// Created by Djorkaeff Alexandre Vilela Pereira on 9/16/20.
|
||
|
// Copyright © 2020 Rocket.Chat. All rights reserved.
|
||
|
//
|
||
|
|
||
|
import Foundation
|
||
|
|
||
|
struct Retry {
|
||
|
let retries: Int
|
||
|
let retryTimeout = [10.0, 5.0, 3.0, 1.0]
|
||
|
|
||
|
init(retries: Int) {
|
||
|
if retries < 0 {
|
||
|
self.retries = 0
|
||
|
} else if retries > retryTimeout.count {
|
||
|
self.retries = retryTimeout.count
|
||
|
} else {
|
||
|
self.retries = retries
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var timeout: Double {
|
||
|
return retryTimeout[retries - 1]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
final class API {
|
||
|
typealias Server = String
|
||
|
|
||
|
final let server: URL
|
||
|
final let credentials: Credentials?
|
||
|
final let decoder = JSONDecoder()
|
||
|
|
||
|
static var instances: [Server: API] = [:]
|
||
|
|
||
|
convenience init?(server: Server) {
|
||
|
guard let server = URL(string: server.removeTrailingSlash()) else {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
self.init(server: server)
|
||
|
}
|
||
|
|
||
|
init(server: URL) {
|
||
|
self.server = server
|
||
|
self.credentials = Storage.shared.getCredentials(server: server.absoluteString)
|
||
|
}
|
||
|
|
||
|
func fetch<T: Request>(request: T, retry: Retry? = nil, completion: @escaping((APIResponse<T.ResponseType>) -> Void)) {
|
||
|
func onError() {
|
||
|
if let retry = retry, retry.retries > 0 {
|
||
|
DispatchQueue.main.asyncAfter(deadline: .now() + retry.timeout, execute: {
|
||
|
self.fetch(request: request, retry: Retry(retries: retry.retries - 1), completion: completion)
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
completion(.error)
|
||
|
}
|
||
|
|
||
|
guard let request = request.request(for: self) else {
|
||
|
completion(.error)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
let task = URLSession.shared.dataTask(with: request) {(data, _, error) in
|
||
|
if let _ = error as NSError? {
|
||
|
onError()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
guard let data = data else {
|
||
|
onError()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if let response = try? self.decoder.decode(T.ResponseType.self, from: data), response.success {
|
||
|
completion(.resource(response))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
onError()
|
||
|
}
|
||
|
|
||
|
task.resume()
|
||
|
}
|
||
|
}
|
||
|
|