83 lines · 2.7 KB · Swift
RawDownload
import Foundation extension UsageStore {    enum StartupBehavior {        case automatic        case full        case testing         var automaticallyStartsBackgroundWork: Bool {            switch self {            case .automatic, .full:                true            case .testing:                false            }        }         func resolved(isRunningTests: Bool) -> StartupBehavior {            switch self {            case .automatic:                isRunningTests ? .testing : .full            case .full, .testing:                self            }        }    }     func recordStartupConnectivityRetryableFailure(_ error: Error) {        guard self.startupConnectivityRetryRefreshActive else { return }        guard Self.isStartupConnectivityRetryableError(error) else { return }        self.startupConnectivityRetryNeeded = true    }     func completeStartupConnectivityRetryPass(currentAttempt: Int) {        guard self.startupConnectivityRetryNeeded else {            self.cancelStartupConnectivityRetry()            return        }         let nextAttempt = currentAttempt + 1        guard let delay = Self.startupConnectivityRetryDelay(forAttempt: nextAttempt) else {            self.cancelStartupConnectivityRetry()            return        }         self.scheduleStartupConnectivityRetry(attempt: nextAttempt, delay: delay)    }     private func scheduleStartupConnectivityRetry(attempt: Int, delay: TimeInterval) {        guard self.startupBehavior.automaticallyStartsBackgroundWork ||            self._test_startupConnectivityRetryScheduled != nil ||            self._test_startupConnectivityRetrySleepOverride != nil        else {            return        }         self.startupConnectivityRetryTask?.cancel()        self._test_startupConnectivityRetryScheduled?(attempt, delay)        self.startupConnectivityRetryTask = Task { @MainActor [weak self] in            guard let self else { return }            do {                try await self.sleepForStartupConnectivityRetry(delay)                guard !Task.isCancelled else { return }                await self.runRefresh(startupConnectivityRetryAttempt: attempt)            } catch {                return            }        }    }     private func cancelStartupConnectivityRetry() {        self.startupConnectivityRetryTask?.cancel()        self.startupConnectivityRetryTask = nil    }     private func sleepForStartupConnectivityRetry(_ delay: TimeInterval) async throws {        if let override = self._test_startupConnectivityRetrySleepOverride {            try await override(delay)            return        }        try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))    }}