Created
December 10, 2022 12:10
-
-
Save hoc081098/806560213b063523e9d475efdd60829d to your computer and use it in GitHub Desktop.
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
// | |
// Demo.swift | |
// PhDownloader Example | |
// | |
// Created by Hoc Nguyen T. on 12/10/22. | |
// | |
import Foundation | |
import RxSwift | |
import RxRelay | |
enum SessionServiceDelegateError: Error { | |
case destroyed | |
} | |
class SessionServiceDelegate { | |
private let isRefreshing = AtomicBoolean() | |
private let tokenRelay = BehaviorRelay<String?>(value: nil) | |
private let tokenScheduler = SerialDispatchQueueScheduler(qos: .userInitiated) | |
/// Get from local storage | |
private func tokenObservable() -> Observable<String?> { | |
tokenRelay.asObservable() | |
} | |
/// Save token to local storage | |
private func saveToken(token: String) -> Completable { | |
.deferred { [tokenRelay] in | |
tokenRelay.accept(token) | |
return .empty() | |
}.subscribe(on: tokenScheduler) | |
} | |
/// Refresh token from server | |
private func refreshToken() -> Single<String> { | |
Single | |
.just("token") | |
.delay( | |
.seconds(3), | |
scheduler: ConcurrentDispatchQueueScheduler.init(qos: .utility) | |
) | |
.do( | |
onSubscribe: { | |
print("getTokenRefreshService >>>> refreshToken start...") | |
}, | |
onDispose: { | |
print("getTokenRefreshService >>>> refreshToken done") | |
} | |
) | |
} | |
func getTokenRefreshService() -> Single<Void> { | |
.deferred { [weak self] in | |
guard let self = self else { return Single.error(SessionServiceDelegateError.destroyed) } | |
if !self.isRefreshing.getAndSet(value: true) { | |
print("getTokenRefreshService [execute]: \(self.isRefreshing.get())") | |
return self.refreshToken() | |
.flatMap { token in | |
self | |
.saveToken(token: token) | |
.andThen(Single.just(())) | |
} | |
.do( | |
onDispose: { | |
_ = self.isRefreshing.getAndSet(value: false) | |
} | |
) | |
} | |
print("getTokenRefreshService [ignore]: \(self.isRefreshing.get())") | |
return self.tokenObservable() | |
.filter { $0 != nil } | |
.take(1) | |
.map { _ in () } | |
.asSingle() | |
} | |
} | |
} | |
typealias Byte = UInt8 | |
class AtomicBoolean { | |
private var val: Byte = 0 | |
/// Sets the value, and returns the previous value. | |
/// The test/set is an atomic operation. | |
func getAndSet(value: Bool) -> Bool { | |
if value { | |
return OSAtomicTestAndSet(0, &val) | |
} else { | |
return OSAtomicTestAndClear(0, &val) | |
} | |
} | |
/// Returns the current value of the boolean. | |
/// The value may change before this method returns. | |
func get() -> Bool { | |
return val != 0 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment