All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jaspercloud.react.mono.AsyncMono Maven / Gradle / Ivy

package io.jaspercloud.react.mono;

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.publisher.BaseSubscriber;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;
import reactor.core.publisher.SignalType;
import reactor.core.scheduler.Scheduler;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

/**
 * 链式处理
 * 当前线程 Schedulers.immediate()
 * 可重用的单线程 Schedulers.single()
 * 弹性线程池 Schedulers.elastic() 该方法是一种将阻塞处理放在一个单独的线程中执行的很好的方式
 * 固定大小线程池 Schedulers.parallel() 该方法创建的线程数量取决于CPU的核数。
 *
 * @param 
 */
public class AsyncMono {

    private Mono input;

    public Mono toMono() {
        return input;
    }

    public AsyncMono() {
        this(Mono.empty());
    }

    public AsyncMono(I data) {
        this(Mono.justOrEmpty(data));
    }

    public AsyncMono(Throwable throwable) {
        this(Mono.error(throwable));
    }

    public AsyncMono(Mono input) {
        this.input = input;
    }

    public AsyncMono(AsyncMono input) {
        this.input = input.toMono();
    }

    public static  AsyncMono create(Consumer> callback) {
        return new AsyncMono<>(Mono.create(sink -> {
            try {
                callback.accept(sink);
            } catch (Throwable e) {
                sink.error(e);
            }
        }));
    }

    /**
     * 异步处理
     *
     * @param call
     * @param 
     * @return
     */
    public  AsyncMono then(ReactAsyncCall call) {
        Mono result = Mono.create(new Consumer>() {
            @Override
            public void accept(MonoSink sink) {
                /**
                 * BaseSubscriber会触发hookFinally
                 * CoreSubscriber、Subscriber不会触发
                 */
                DefaultReactSink reactSink = new DefaultReactSink(sink);
                AtomicBoolean status = new AtomicBoolean(false);
                input.subscribe(new BaseSubscriber() {

                    @Override
                    protected void hookOnSubscribe(Subscription subscription) {
                        sink.onRequest(e -> {
                            call.onSubscribe();
                            subscription.request(e);
                        });
                    }

                    @Override
                    protected void hookOnNext(I next) {
                        reactSink.setResult(next);
                        try {
                            call.process(false, null, next, reactSink);
                        } catch (Throwable t) {
                            reactSink.error(t);
                        } finally {
                            status.set(true);
                        }
                    }

                    @Override
                    protected void hookOnError(Throwable throwable) {
                        reactSink.setThrowable(throwable);
                        try {
                            call.process(true, throwable, null, reactSink);
                        } catch (Throwable t) {
                            reactSink.error(t);
                        } finally {
                            status.set(true);
                        }
                    }

                    @Override
                    protected void hookFinally(SignalType type) {
                        if (status.compareAndSet(false, true)) {
                            try {
                                call.process(null != reactSink.getThrowable(), reactSink.getThrowable(), (I) reactSink.getResult(), reactSink);
                            } catch (Throwable t) {
                                reactSink.error(t);
                            }
                        }
                        call.onFinally();
                    }
                });
            }
        });
        return new AsyncMono<>(result);
    }

    public AsyncMono timeout(long timeout) {
        return new AsyncMono<>(input.timeout(Duration.ofMillis(timeout)));
    }

    /**
     * 影响在其之后的 operator执行的线程池
     *
     * @param scheduler
     * @return
     */
    public AsyncMono publishOn(Scheduler scheduler) {
        return new AsyncMono<>(input.publishOn(scheduler));
    }

    /**
     * 源头影响整个执行过程
     *
     * @param scheduler
     * @return
     */
    public AsyncMono subscribeOn(Scheduler scheduler) {
        return new AsyncMono<>(input.subscribeOn(scheduler));
    }

    public void subscribe(Consumer success) {
        input.subscribe(new BaseSubscriber() {
            @Override
            protected void hookOnNext(I value) {
                success.accept(value);
            }
        });
    }

    public void subscribe(Consumer success, Consumer error) {
        input.subscribe(new BaseSubscriber() {
            @Override
            protected void hookOnNext(I value) {
                success.accept(value);
            }

            @Override
            protected void hookOnError(Throwable throwable) {
                error.accept(throwable);
            }
        });
    }

    public void subscribe(Subscriber actual) {
        input.subscribe(actual);
    }

    public void subscribe(ReactSink sink) {
        input.subscribe(new BaseSubscriber() {
            @Override
            protected void hookOnNext(I value) {
                sink.success(value);
            }

            @Override
            protected void hookOnError(Throwable throwable) {
                sink.error(throwable);
            }
        });
    }

    public void subscribe() {
        input.subscribe();
    }

}