NetworkClient.swift 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import Foundation
  2. enum NetworkClient {
  3. static let session: URLSession = {
  4. let configuration = URLSessionConfiguration.default
  5. configuration.waitsForConnectivity = true
  6. configuration.timeoutIntervalForRequest = 60
  7. configuration.timeoutIntervalForResource = 120
  8. configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
  9. return URLSession(configuration: configuration)
  10. }()
  11. static func data(for request: URLRequest, retries: Int = 2) async throws -> (Data, URLResponse) {
  12. var lastError: Error?
  13. for attempt in 0...retries {
  14. if attempt > 0 {
  15. try await Task.sleep(nanoseconds: UInt64(attempt) * 400_000_000)
  16. }
  17. do {
  18. return try await session.data(for: request)
  19. } catch let error as URLError where error.isTransientNetworkFailure {
  20. lastError = error
  21. } catch {
  22. throw error
  23. }
  24. }
  25. throw lastError ?? URLError(.unknown)
  26. }
  27. static func prepare() async {
  28. guard let url = URL(string: "https://api.openai.com") else { return }
  29. var request = URLRequest(url: url)
  30. request.httpMethod = "HEAD"
  31. request.timeoutInterval = 15
  32. _ = try? await session.data(for: request)
  33. }
  34. }
  35. private extension URLError {
  36. var isTransientNetworkFailure: Bool {
  37. switch code {
  38. case .networkConnectionLost,
  39. .notConnectedToInternet,
  40. .timedOut,
  41. .cannotConnectToHost,
  42. .dnsLookupFailed,
  43. .cannotFindHost,
  44. .internationalRoamingOff,
  45. .callIsActive:
  46. return true
  47. default:
  48. return false
  49. }
  50. }
  51. }