| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- import Foundation
- enum NetworkClient {
- static let session: URLSession = {
- let configuration = URLSessionConfiguration.default
- configuration.waitsForConnectivity = true
- configuration.timeoutIntervalForRequest = 60
- configuration.timeoutIntervalForResource = 120
- configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
- return URLSession(configuration: configuration)
- }()
- /// Low-latency session for AI API calls — does not block waiting for connectivity.
- static let aiSession: URLSession = {
- let configuration = URLSessionConfiguration.default
- configuration.waitsForConnectivity = false
- configuration.timeoutIntervalForRequest = 45
- configuration.timeoutIntervalForResource = 60
- configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
- configuration.httpMaximumConnectionsPerHost = 4
- return URLSession(configuration: configuration)
- }()
- static func data(
- for request: URLRequest,
- session: URLSession = session,
- retries: Int = 2
- ) async throws -> (Data, URLResponse) {
- var lastError: Error?
- for attempt in 0...retries {
- if attempt > 0 {
- try await Task.sleep(nanoseconds: UInt64(attempt) * 400_000_000)
- }
- do {
- return try await session.data(for: request)
- } catch let error as URLError where error.isTransientNetworkFailure {
- lastError = error
- } catch {
- throw error
- }
- }
- throw lastError ?? URLError(.unknown)
- }
- static func aiData(for request: URLRequest) async throws -> (Data, URLResponse) {
- try await data(for: request, session: aiSession, retries: 0)
- }
- static func prepare() async {
- guard let url = URL(string: "https://api.openai.com") else { return }
- var request = URLRequest(url: url)
- request.httpMethod = "HEAD"
- request.timeoutInterval = 10
- _ = try? await aiSession.data(for: request)
- }
- }
- private extension URLError {
- var isTransientNetworkFailure: Bool {
- switch code {
- case .networkConnectionLost,
- .notConnectedToInternet,
- .timedOut,
- .cannotConnectToHost,
- .dnsLookupFailed,
- .cannotFindHost,
- .internationalRoamingOff,
- .callIsActive:
- return true
- default:
- return false
- }
- }
- }
|