mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-09 22:35:56 +05:45
113 lines
3.5 KiB
Swift
113 lines
3.5 KiB
Swift
//
|
|
// HTTPRequestTimeoutManager.swift
|
|
// RevenueCat
|
|
//
|
|
// Created by Rick van der Linden on 06/11/2025.
|
|
// Copyright © 2025 RevenueCat, Inc. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
protocol HTTPRequestTimeoutManagerType {
|
|
|
|
/// Determines the timeout to be used by the HTTP Request for the given path.
|
|
///
|
|
/// - Parameters:
|
|
/// - isFallback: Whether this is a fallback request
|
|
/// - fallbackAvailable: Whether fallback URLs are available for this request
|
|
/// - Returns: The timeout interval in seconds
|
|
func timeout(isFallback: Bool, fallbackAvailable: Bool) -> TimeInterval
|
|
|
|
/// Updates the internal state in response to the result received from the backend.
|
|
///
|
|
/// - Parameter result: The result of the HTTP request
|
|
func recordRequestResult(_ result: HTTPRequestTimeoutManager.RequestResult)
|
|
}
|
|
|
|
class HTTPRequestTimeoutManager: HTTPRequestTimeoutManagerType {
|
|
|
|
enum RequestResult {
|
|
|
|
/// Request succeeded on the main backend
|
|
case successOnMainBackend
|
|
|
|
/// Request timed out on the main backend endpoint and supports fallback URLs
|
|
case timeoutOnMainBackendForFallbackSupportedEndpoint
|
|
|
|
/// Any other result (non-main backend, non-timeout errors, etc.)
|
|
case other
|
|
}
|
|
|
|
enum Timeout: TimeInterval {
|
|
|
|
/// The default timeout for backend requests that support a fallback
|
|
case mainBackendRequestSupportingFallback = 5
|
|
|
|
/// The reduced timeout for requests with fallback support after timeout
|
|
case reduced = 2
|
|
}
|
|
|
|
// The amount of time after which the 'last timeout request received' state can be reset
|
|
private static let timeoutResetInterval: TimeInterval = 600 // 10 minutes
|
|
|
|
// The last time at which a timeout was received from the main backend
|
|
private var lastTimeoutRequestTime: Date?
|
|
|
|
// The default timeout to use
|
|
private let defaultTimeout: TimeInterval
|
|
|
|
private let dateProvider: DateProvider
|
|
|
|
init(
|
|
defaultTimeout: TimeInterval,
|
|
dateProvider: DateProvider = .init()
|
|
) {
|
|
self.defaultTimeout = defaultTimeout
|
|
self.dateProvider = dateProvider
|
|
}
|
|
|
|
func timeout(isFallback: Bool, fallbackAvailable: Bool) -> TimeInterval {
|
|
if shouldResetTimeout {
|
|
resetLastTimeoutRequestTime()
|
|
}
|
|
|
|
let timeout: TimeInterval
|
|
|
|
if isFallback || !fallbackAvailable {
|
|
timeout = self.defaultTimeout
|
|
}
|
|
// Main backend request that supports fallback when a timeout was previously received from the main backend
|
|
else if lastTimeoutRequestTime != nil {
|
|
timeout = Timeout.reduced.rawValue
|
|
}
|
|
// Main backend request that supports fallback, no timeout received recently
|
|
else {
|
|
timeout = Timeout.mainBackendRequestSupportingFallback.rawValue
|
|
}
|
|
|
|
return timeout
|
|
}
|
|
|
|
func recordRequestResult(_ result: RequestResult) {
|
|
switch result {
|
|
case .successOnMainBackend:
|
|
resetLastTimeoutRequestTime()
|
|
case .timeoutOnMainBackendForFallbackSupportedEndpoint:
|
|
lastTimeoutRequestTime = dateProvider.now()
|
|
case .other:
|
|
break
|
|
}
|
|
}
|
|
|
|
private func resetLastTimeoutRequestTime() {
|
|
lastTimeoutRequestTime = nil
|
|
}
|
|
|
|
private var shouldResetTimeout: Bool {
|
|
guard let lastTimeoutRequestTime else { return false }
|
|
|
|
let timeElapsed = dateProvider.now().timeIntervalSince(lastTimeoutRequestTime)
|
|
return timeElapsed >= Self.timeoutResetInterval
|
|
}
|
|
}
|