Last active
August 26, 2021 20:34
-
-
Save marty-suzuki/96f9d6cd0c4419555b5eac7c4b34cbd6 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
import Combine | |
import FirebaseAuth | |
public struct CombineAuth { | |
fileprivate let auth: Auth | |
} | |
extension CombineAuth { | |
public enum Error: Swift.Error { | |
case userNotFound | |
} | |
public final class Subscription<S: Subscriber>: Combine.Subscription where S.Input == (Auth, User), S.Failure == Error { | |
private var subscriber: S? | |
private let auth: Auth | |
private let _cancel: (Auth) -> Void | |
fileprivate init(subscriber: S, | |
auth: Auth, | |
addListener: @escaping (Auth, @escaping (Auth, User?) -> Void) -> NSObjectProtocol, | |
removeListener: @escaping (Auth, NSObjectProtocol) -> Void) { | |
self.subscriber = subscriber | |
self.auth = auth | |
let listener = addListener(auth) { auth, user in | |
if let user = user { | |
_ = subscriber.receive((auth, user)) | |
} else { | |
subscriber.receive(completion: .failure(.userNotFound)) | |
} | |
} | |
self._cancel = { removeListener($0, listener) } | |
} | |
public func request(_ demand: Subscribers.Demand) {} | |
public func cancel() { | |
_cancel(auth) | |
subscriber = nil | |
} | |
} | |
public struct Publisher: Combine.Publisher { | |
public typealias Output = (Auth, User) | |
public typealias Failure = Error | |
private let auth: Auth | |
private let addListener: (Auth, @escaping (Auth, User?) -> Void) -> NSObjectProtocol | |
private let removeListener: (Auth, NSObjectProtocol) -> Void | |
init(auth: Auth, | |
addListener: @escaping (Auth, @escaping (Auth, User?) -> Void) -> NSObjectProtocol, | |
removeListener: @escaping (Auth, NSObjectProtocol) -> Void) { | |
self.auth = auth | |
self.addListener = addListener | |
self.removeListener = removeListener | |
} | |
public func receive<S>(subscriber: S) where S : Subscriber, S.Failure == Failure, S.Input == Output { | |
let subscription = Subscription(subscriber: subscriber, | |
auth: auth, | |
addListener: addListener, | |
removeListener: removeListener) | |
subscriber.receive(subscription: subscription) | |
} | |
} | |
} | |
extension Auth { | |
public var combine: CombineAuth { | |
return CombineAuth(auth: self) | |
} | |
} | |
extension CombineAuth { | |
public func stateDidChange() -> AnyPublisher<(Auth, User), Error> { | |
return Publisher(auth: auth, | |
addListener: { $0.addStateDidChangeListener($1) }, | |
removeListener: { $0.removeStateDidChangeListener($1) }) | |
.eraseToAnyPublisher() | |
} | |
public func idTokenDidChange() -> AnyPublisher<(Auth, User), Error> { | |
return Publisher(auth: auth, | |
addListener: { $0.addIDTokenDidChangeListener($1) }, | |
removeListener: { $0.removeIDTokenDidChangeListener($1) }) | |
.eraseToAnyPublisher() | |
} | |
} | |
func doIt() { | |
class Store { | |
var user: User? | |
} | |
let store = Store() | |
let cancellable = Auth.auth().combine.stateDidChange() | |
.map { $1 } | |
.catch { _ in Just(Optional<User>.none) } | |
.assign(to: \.user, on: store) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment