Created
January 23, 2021 00:52
-
-
Save AdieOlami/dcf2570081f68b542b1841c214beec07 to your computer and use it in GitHub Desktop.
Migrating Moya RxSwift to Combine exposing every process.
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
class OnlineProvider<Target> where Target: Moya.TargetType { | |
fileprivate let provider: MoyaProvider<Target> | |
fileprivate let reachabilityManager: ReachabilityManager | |
private let authManager: AuthManager | |
init(endpointClosure: @escaping MoyaProvider<Target>.EndpointClosure = MoyaProvider<Target>.defaultEndpointMapping, | |
requestClosure: @escaping MoyaProvider<Target>.RequestClosure = MoyaProvider<Target>.defaultRequestMapping, | |
stubClosure: @escaping MoyaProvider<Target>.StubClosure = MoyaProvider<Target>.neverStub, | |
session: Session = MoyaProvider<Target>.defaultAlamofireSession(), | |
trackInflights: Bool = false, | |
reachabilityManager: ReachabilityManager, | |
authManager: AuthManager | |
) { | |
self.reachabilityManager = reachabilityManager | |
self.authManager = authManager | |
self.provider = MoyaProvider(endpointClosure: endpointClosure, requestClosure: requestClosure, stubClosure: stubClosure, session: session, plugins: [NetworkLoggerPlugin()], trackInflights: trackInflights) | |
} | |
func request(_ token: Target) -> Observable<Moya.Response> { | |
let actualRequest = provider.rx.request(token) | |
return reachabilityManager | |
.connectionIsReachable | |
.ignore(value: false) // Wait until we're online | |
.take(1) // Take 1 to make sure we only invoke the API once. | |
.flatMap { _ in // Turn the online state into a network request | |
return actualRequest | |
.filterSuccessfulStatusCodes() | |
.do(onSuccess: {(response) in | |
}, onError: {[weak self] (error) in | |
if let error = error as? MoyaError, let self = self { | |
switch error { | |
case .statusCode(let response): | |
if response.statusCode == 401 { | |
// Unauthorized | |
// if self.authManager.isAuthorized { | |
// AuthManager.removeToken() | |
// Application.shared.presentInitialScreen(in: Application.shared.window) | |
// } | |
} | |
default: break | |
} | |
} | |
}) | |
} | |
} | |
func request2(_ token: Target) -> AnyPublisher<Moya.Response, MoyaError> { | |
let actualRequest = provider.requestPublisher(token) | |
return reachabilityManager | |
.isReachable | |
.ignore(value: false) | |
.prefix(1) | |
.flatMap{ _ in | |
return actualRequest | |
.filterSuccessfulStatusCodes() | |
.handleEvents { (response) in | |
// | |
} receiveCompletion: {[weak self] (error) in | |
switch error { | |
case.failure(let failure): | |
switch failure { | |
case .statusCode(let response): | |
if response.statusCode == 401 { | |
} | |
default: break | |
} | |
default: break | |
} | |
} | |
} | |
.eraseToAnyPublisher() | |
} | |
} | |
protocol NetworkingType { | |
associatedtype T: TargetType | |
var provider: OnlineProvider<T> { get } | |
static func defaultNetworking() -> Self | |
// static func stubbingNetworking() -> Self | |
} | |
struct AuthNetworking: NetworkingType { | |
typealias T = AuthApi | |
let provider: OnlineProvider<T> | |
static func defaultNetworking() -> Self { | |
return AuthNetworking(provider: newAuthProvider()) | |
} | |
func request(_ token: T) -> Observable<Moya.Response> { | |
return self.provider.request(token) | |
} | |
func request2(_ token: T) -> AnyPublisher<Moya.Response, MoyaError> { | |
return self.provider.request2(token) | |
} | |
} | |
struct HomeNetworking: NetworkingType { | |
typealias T = HomeAPI | |
let provider: OnlineProvider<T> | |
static func defaultNetworking() -> Self { | |
return HomeNetworking(provider: newProvider()) | |
} | |
func request(_ token: T) -> Observable<Moya.Response> { | |
return self.provider.request(token) | |
} | |
func request2(_ token: T) -> AnyPublisher<Moya.Response, MoyaError> { | |
return self.provider.request2(token) | |
} | |
} | |
protocol AuthDataSource { | |
func login(credentials: Credentials) -> Single<BaseResponseData<AuthResponse>> | |
func login2(credentials: Credentials) -> Future<BaseResponseData<AuthResponse>, MoyaError> | |
} | |
class AuthRepository: AuthDataSource { | |
let authProvider: AuthNetworking | |
init(authProvider: AuthNetworking) { | |
self.authProvider = authProvider | |
} | |
} | |
extension AuthRepository { | |
func login2(credentials: Credentials) -> Future<BaseResponseData<AuthResponse>, MoyaError> { | |
return requestObject2(.login(phoneNumber: credentials.phoneNumber, password: credentials.password), type: AuthResponse.self) | |
} | |
func login(credentials: Credentials) -> Single<BaseResponseData<AuthResponse>> { | |
return requestObject(.login(phoneNumber: credentials.phoneNumber, password: credentials.password), type: AuthResponse.self) | |
} | |
} | |
extension AuthRepository { | |
private func request(_ target: AuthApi) -> Single<Any> { | |
return authProvider.request(target) | |
.mapJSON() | |
.observeOn(MainScheduler.instance) | |
.asSingle() | |
} | |
private func requestObject<T: Codable>(_ target: AuthApi, type: T.Type) -> Single<BaseResponseData<T>> { | |
return authProvider.request(target) | |
.mapObject(BaseResponseData<T>.self) | |
.observeOn(MainScheduler.instance) | |
.asSingle() | |
} | |
private func requestObject2<T: Codable>(_ target: AuthApi, type: T.Type) -> Future<BaseResponseData<T>, MoyaError> { | |
return authProvider.request2(target) | |
.mapObject(BaseResponseData<T>.self) | |
.receive(on: RunLoop.main) | |
.asFuture() | |
} | |
} | |
extension Publisher { | |
func asFuture() -> Future<Output, Failure> { | |
return Future { promise in | |
var ticket: AnyCancellable? = nil | |
ticket = self.sink( | |
receiveCompletion: { | |
ticket?.cancel() | |
ticket = nil | |
switch $0 { | |
case .failure(let error): | |
promise(.failure(error)) | |
case .finished: | |
// WHAT DO WE DO HERE??? | |
fatalError() | |
} | |
}, | |
receiveValue: { | |
ticket?.cancel() | |
ticket = nil | |
promise(.success($0)) | |
}) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment