package com.apollographql.apollo.rx; import com.apollographql.apollo.ApolloCall; import com.apollographql.apollo.ApolloPrefetch; import com.apollographql.apollo.ApolloQueryWatcher; import com.apollographql.apollo.api.Response; import com.apollographql.apollo.exception.ApolloException; import com.apollographql.apollo.internal.util.Cancelable; import javax.annotation.Nonnull; import rx.Completable; import rx.CompletableSubscriber; import rx.Emitter; import rx.Observable; import rx.Single; import rx.SingleSubscriber; import rx.Subscription; import rx.exceptions.Exceptions; import rx.functions.Action0; import rx.functions.Action1; import rx.functions.Cancellable; import rx.subscriptions.Subscriptions; import static com.apollographql.apollo.api.internal.Utils.checkNotNull; /** * The RxApollo class provides methods for converting ApolloCall * and ApolloWatcher types to RxJava 1 Observables. */ public final class RxApollo { private RxApollo() { } /** * Converts an {@link ApolloQueryWatcher} into an Observable. Honors the back pressure from downstream with the back * pressure strategy {@link rx.Emitter.BackpressureMode#LATEST}. * * @param watcher the ApolloQueryWatcher to convert * @param <T> the value type * @return the converted Observable */ @Nonnull public static <T> Observable<Response<T>> from(@Nonnull final ApolloQueryWatcher<T> watcher) { return from(watcher, Emitter.BackpressureMode.LATEST); } /** * Converts an {@link ApolloQueryWatcher} into an Observable. * * @param watcher the ApolloQueryWatcher to convert * @param backpressureMode the back pressure strategy to apply to the observable source. * @param <T> the value type * @return the converted Observable */ @Nonnull public static <T> Observable<Response<T>> from(@Nonnull final ApolloQueryWatcher<T> watcher, @Nonnull Emitter.BackpressureMode backpressureMode) { checkNotNull(backpressureMode, "backpressureMode == null"); checkNotNull(watcher, "watcher == null"); return Observable.create(new Action1<Emitter<Response<T>>>() { @Override public void call(final Emitter<Response<T>> emitter) { emitter.setCancellation(new Cancellable() { @Override public void cancel() throws Exception { watcher.cancel(); } }); watcher.enqueueAndWatch(new ApolloCall.Callback<T>() { @Override public void onResponse(@Nonnull Response<T> response) { emitter.onNext(response); } @Override public void onFailure(@Nonnull ApolloException e) { Exceptions.throwIfFatal(e); emitter.onError(e); } }); } }, backpressureMode); } /** * Converts an {@link ApolloCall} to a Single. * * @param call the ApolloCall to convert * @param <T> the value type * @return the converted Single */ @Nonnull public static <T> Single<Response<T>> from(@Nonnull final ApolloCall<T> call) { checkNotNull(call, "call == null"); return Single.create(new Single.OnSubscribe<Response<T>>() { @Override public void call(SingleSubscriber<? super Response<T>> subscriber) { cancelOnSingleUnsubscribe(subscriber, call); try { Response<T> response = call.execute(); if (!subscriber.isUnsubscribed()) { subscriber.onSuccess(response); } } catch (ApolloException e) { Exceptions.throwIfFatal(e); if (!subscriber.isUnsubscribed()) { subscriber.onError(e); } } } }); } /** * Converts an {@link ApolloPrefetch} to a Completable. * * @param prefetch the ApolloPrefetch to convert * @return the converted Completable */ @Nonnull public static Completable from(@Nonnull final ApolloPrefetch prefetch) { checkNotNull(prefetch, "prefetch == null"); return Completable.create(new Completable.OnSubscribe() { @Override public void call(final CompletableSubscriber subscriber) { Subscription subscription = getSubscription(subscriber, prefetch); try { prefetch.execute(); if (!subscription.isUnsubscribed()) { subscriber.onCompleted(); } } catch (ApolloException e) { Exceptions.throwIfFatal(e); if (!subscription.isUnsubscribed()) { subscriber.onError(e); } } } }); } private static Subscription getSubscription(CompletableSubscriber subscriber, final Cancelable cancelable) { Subscription subscription = Subscriptions.create(new Action0() { @Override public void call() { cancelable.cancel(); } }); subscriber.onSubscribe(subscription); return subscription; } private static <T> void cancelOnSingleUnsubscribe(SingleSubscriber<? super T> subscriber, final Cancelable toCancel) { subscriber.add(Subscriptions.create(new Action0() { @Override public void call() { toCancel.cancel(); } })); } }