Files
purchases-ios/Sources/Networking/Operations/GetRemoteConfigFallbackOperation.swift
T
Rick b82223e5a1 feat(remote-config): add static fallback config endpoint (#7182)
* feat(remote-config): add static fallback config endpoint

* refactor(remote-config): clarify static fallback path name

* test(remote-config): cover static fallback signature failures

* fix(remote-config): use static fallback only without cache

* test(remote-config): cover static fallback external blobs

* refactor(remote-config): align static fallback naming

* refactor(remote-config): scope static fallback path

* fix(remote-config): mark fallback no content fresh

* fix(remote-config): align fallback accept headers

* refactor(remote-config): rename fallback endpoint types

* fix(remote-config): enable etags for fallback config

* fix(remote-config): skip fallback when proxy is configured

* fix(remote-config): rely on etag cache for fallback

* refactor(remote-config): reuse fallback retry eligibility

* fix(remote-config): disable after fallback client errors
2026-07-10 14:17:31 +02:00

73 lines
2.3 KiB
Swift

//
// GetRemoteConfigFallbackOperation.swift
// RevenueCat
//
// Created by Rick van der Linden on 09/07/2026.
// Copyright © 2026 RevenueCat, Inc. All rights reserved.
//
import Foundation
final class GetRemoteConfigFallbackOperation: CacheableNetworkOperation {
private let callbackCache: CallbackCache<RemoteConfigFallbackCallback>
private let domain: String
static func createFactory(
configuration: NetworkConfiguration,
callbackCache: CallbackCache<RemoteConfigFallbackCallback>,
domain: String
) -> CacheableNetworkOperationFactory<GetRemoteConfigFallbackOperation> {
return .init({ cacheKey in
.init(
configuration: configuration,
callbackCache: callbackCache,
domain: domain,
cacheKey: cacheKey
)
},
individualizedCacheKeyPart: "domain=\(domain)")
}
private init(
configuration: NetworkConfiguration,
callbackCache: CallbackCache<RemoteConfigFallbackCallback>,
domain: String,
cacheKey: String
) {
self.callbackCache = callbackCache
self.domain = domain
super.init(configuration: configuration, cacheKey: cacheKey)
}
override func begin(completion: @escaping () -> Void) {
self.getRemoteConfigFallback(completion: completion)
}
}
// Restating inherited @unchecked Sendable from Foundation's Operation
extension GetRemoteConfigFallbackOperation: @unchecked Sendable {}
private extension GetRemoteConfigFallbackOperation {
func getRemoteConfigFallback(completion: @escaping () -> Void) {
let request = HTTPRequest(method: .get, path: HTTPRequest.FallbackPath.remoteConfig(domain: self.domain))
self.httpClient.perform(request) { (response: VerifiedHTTPResponse<RemoteConfiguration>.Result) in
defer {
completion()
}
self.callbackCache.performOnAllItemsAndRemoveFromCache(withCacheable: self) { callback in
callback.completion(
response
.map(RemoteConfigFallbackFetchResult.init(response:))
.mapError(BackendError.networkError)
)
}
}
}
}