package it.tdlight.utils; import io.reactivex.Completable; import io.reactivex.Flowable; import io.reactivex.Maybe; import io.reactivex.Observable; import io.reactivex.Single; import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.reactivex.RxHelper; import io.vertx.reactivex.core.eventbus.Message; import io.vertx.reactivex.core.eventbus.MessageConsumer; import io.vertx.reactivex.core.streams.Pipe; import io.vertx.reactivex.core.streams.ReadStream; import io.vertx.reactivex.core.streams.WriteStream; import it.tdlight.jni.TdApi; import it.tdlight.jni.TdApi.Chat; import it.tdlight.tdlibsession.td.TdError; import it.tdlight.tdlibsession.td.TdResult; import java.time.Duration; import java.util.Objects; import java.util.Optional; import java.util.Queue; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Supplier; import org.apache.commons.lang3.NotImplementedException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.reactivestreams.Publisher; import org.reactivestreams.Subscription; import org.warp.commonutils.concurrency.future.CompletableFutureUtils; import org.warp.commonutils.functional.IOConsumer; import org.warp.commonutils.log.Logger; import org.warp.commonutils.log.LoggerFactory; import reactor.adapter.rxjava.RxJava2Adapter; import reactor.core.CoreSubscriber; import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink.OverflowStrategy; import reactor.core.publisher.Mono; import reactor.core.publisher.MonoSink; import reactor.core.publisher.Sinks; import reactor.core.publisher.Sinks.EmissionException; import reactor.core.publisher.Sinks.EmitResult; import reactor.core.publisher.Sinks.Empty; import reactor.core.publisher.Sinks.Many; import reactor.core.publisher.Sinks.One; import reactor.core.publisher.SynchronousSink; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; import reactor.util.concurrent.Queues; import reactor.util.context.Context; public class MonoUtils { private static final Logger logger = LoggerFactory.getLogger(MonoUtils.class); public static Mono notImplemented() { return Mono.fromCallable(() -> { throw new NotImplementedException(); }); } public static Mono fromBlockingMaybe(Callable callable) { return Mono.fromCallable(callable).subscribeOn(Schedulers.boundedElastic()); } public static Mono fromBlockingEmpty(EmptyCallable callable) { return Mono.fromCallable(() -> { callable.call(); return null; }).subscribeOn(Schedulers.boundedElastic()); } public static Mono fromBlockingSingle(Callable callable) { return fromBlockingMaybe(callable).single(); } public static void orElseThrow(TdResult value, SynchronousSink sink) { if (value.succeeded()) { sink.next(value.result()); } else { sink.error(new TdError(value.cause().code, value.cause().message)); } } public static Mono thenOrError(Mono> optionalMono) { return optionalMono.handle((optional, sink) -> { if (optional.succeeded()) { sink.complete(); } else { sink.error(new TdError(optional.cause().code, optional.cause().message)); } }); } @Deprecated public static Mono toMono(Future future) { return Mono.fromCompletionStage(future.toCompletionStage()); } @Deprecated @NotNull public static Mono toMono(Single single) { return RxJava2Adapter.singleToMono(single); } @Deprecated @NotNull public static Mono toMono(Maybe maybe) { return RxJava2Adapter.maybeToMono(maybe); } @Deprecated @NotNull public static Mono toMono(Completable completable) { //noinspection unchecked return (Mono) RxJava2Adapter.completableToMono(completable); } public static Flux fromMessageConsumer(Mono onRegistered, MessageConsumer messageConsumer) { return fromReplyableMessageConsumer(onRegistered, messageConsumer).map(Message::body); } public static Flux> fromReplyableMessageConsumer(Mono onRegistered, MessageConsumer messageConsumer) { var registration = messageConsumer .rxCompletionHandler().to(RxJava2Adapter::completableToMono) .doFirst(() -> logger.trace("Waiting for consumer registration completion...")) .doOnSuccess(s -> logger.trace("Consumer registered")) .then(onRegistered); var messages = messageConsumer.toFlowable().to(RxJava2Adapter::flowableToFlux); return messages.mergeWith(registration.then(Mono.empty())); } public static Scheduler newBoundedSingle(String name) { return newBoundedSingle(name, false); } public static Scheduler newBoundedSingle(String name, boolean daemon) { return Schedulers.newBoundedElastic(1, Schedulers.DEFAULT_BOUNDED_ELASTIC_QUEUESIZE, name, Integer.MAX_VALUE, daemon ); } public static Mono> toOptional(Mono mono) { return mono.map(Optional::of).defaultIfEmpty(Optional.empty()); } public static Mono isSet(Mono mono) { return mono .map(res -> true) .defaultIfEmpty(false); } }