Last active
January 14, 2023 19:18
-
-
Save ricardopsantos/ce6a2f2eb4444fc61e73c2ae6ae5416d to your computer and use it in GitHub Desktop.
Article_13_G7.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public typealias GenericRequestWithCacheResponse<T1: Codable, E1: Error> = AnyPublisher<T1, E1> | |
public extension NetworkinNameSpace.NetworkingUtils { | |
static func genericRequestWithCache<T1: Codable, E1: Error, T2: Codable, E2: Error>( | |
_ publisher: AnyPublisher<T2, E2>, | |
_ type: T1.Type, | |
_ cachePolicy: CachePolicy, | |
_ serviceKey: String, | |
_ serviceParams: [String], | |
_ cacheManager: CodableCacheManagerProtocol = SimpleCacheManagerForCodable.shared) -> GenericRequestWithCacheResponse<T1, E1> { | |
let lock = { | |
AvailabilityState.lockForServiceKey(serviceKey) | |
} | |
let unlock = { | |
AvailabilityState.unLockForServiceKey(serviceKey) | |
} | |
// Fetch for CACHED data | |
func cacheDontLoad() -> GenericRequestWithCacheResponse<T1, E1> { | |
if let storedModel = cacheManager.syncRetrieve(type, | |
key: serviceKey, | |
params: serviceParams) { | |
return Just(storedModel.model).setFailureType(to: E1.self).eraseToAnyPublisher() | |
} else { | |
return .empty() | |
} | |
} | |
// Fetch for NEW data | |
func noCacheDoLoad() -> GenericRequestWithCacheResponse<T1, E1> { | |
lock() | |
return publisher.onErrorComplete() | |
.flatMap({ model -> GenericRequestWithCacheResponse<T1, E1> in | |
cacheManager.syncStore(model, key: serviceKey, params: serviceParams, timeToLiveMinutes: nil) | |
unlock() | |
if let model = model as? T1 { | |
return Just(model).setFailureType(to: E1.self).eraseToAnyPublisher() | |
} else { | |
return .empty() | |
} | |
}) | |
.catch({ error -> GenericRequestWithCacheResponse<T1, E1> in | |
unlock() | |
return Fail(error: error).eraseToAnyPublisher() | |
}).eraseToAnyPublisher() | |
} | |
// Fetch for NEW data, OR wait for cache data to change and | |
func noCacheDoLoadOrWait() -> GenericRequestWithCacheResponse<T1, E1> { | |
switch AvailabilityState.serviceStates[serviceKey]?.value ?? .free { | |
case .free: return noCacheDoLoad() | |
case .refreshing: return awaitForCache() | |
} | |
} | |
// Theres allready a request on the way. Lets wait for it to end and then return the cached value | |
func awaitForCache() -> GenericRequestWithCacheResponse<T1, E1> { | |
return AvailabilityState.serviceStates[serviceKey]!.filter({ $0 == .free }) | |
.flatMap { _ in return | |
cacheDontLoad() | |
}.eraseToAnyPublisher() | |
} | |
switch cachePolicy { | |
case .ignoringCache: | |
return noCacheDoLoadOrWait() | |
case .cacheElseLoad: | |
return cacheDontLoad().catch { _ -> GenericRequestWithCacheResponse<T1, E1> in | |
return noCacheDoLoadOrWait() | |
}.eraseToAnyPublisher() | |
case .cacheAndLoad: | |
let cacheDontLoad = cacheDontLoad().onErrorComplete().setFailureType(to: E1.self).eraseToAnyPublisher() | |
return Publishers.Merge(cacheDontLoad, noCacheDoLoadOrWait()).eraseToAnyPublisher() | |
case .cacheDontLoad: | |
return cacheDontLoad() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment