tdlib-session-container/src/main/java/it/tdlight/utils/MonoUtils.java

164 lines
5.2 KiB
Java

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 <T> Mono<T> notImplemented() {
return Mono.fromCallable(() -> {
throw new NotImplementedException();
});
}
public static <T> Mono<T> fromBlockingMaybe(Callable<T> callable) {
return Mono.fromCallable(callable).subscribeOn(Schedulers.boundedElastic());
}
public static Mono<Void> fromBlockingEmpty(EmptyCallable callable) {
return Mono.<Void>fromCallable(() -> {
callable.call();
return null;
}).subscribeOn(Schedulers.boundedElastic());
}
public static <T> Mono<T> fromBlockingSingle(Callable<T> callable) {
return fromBlockingMaybe(callable).single();
}
public static <T extends TdApi.Object> void orElseThrow(TdResult<T> value, SynchronousSink<T> sink) {
if (value.succeeded()) {
sink.next(value.result());
} else {
sink.error(new TdError(value.cause().code, value.cause().message));
}
}
public static <T extends TdApi.Object> Mono<Void> thenOrError(Mono<TdResult<T>> 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 <T> Mono<T> toMono(Future<T> future) {
return Mono.fromCompletionStage(future.toCompletionStage());
}
@Deprecated
@NotNull
public static <T> Mono<T> toMono(Single<T> single) {
return RxJava2Adapter.singleToMono(single);
}
@Deprecated
@NotNull
public static <T> Mono<T> toMono(Maybe<T> maybe) {
return RxJava2Adapter.maybeToMono(maybe);
}
@Deprecated
@NotNull
public static <T> Mono<T> toMono(Completable completable) {
//noinspection unchecked
return (Mono<T>) RxJava2Adapter.completableToMono(completable);
}
public static <T> Flux<T> fromMessageConsumer(Mono<Void> onRegistered, MessageConsumer<T> messageConsumer) {
return fromReplyableMessageConsumer(onRegistered, messageConsumer).map(Message::body);
}
public static <T> Flux<Message<T>> fromReplyableMessageConsumer(Mono<Void> onRegistered,
MessageConsumer<T> 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 <R> Mono<Optional<R>> toOptional(Mono<R> mono) {
return mono.map(Optional::of).defaultIfEmpty(Optional.empty());
}
public static <T> Mono<Boolean> isSet(Mono<T> mono) {
return mono
.map(res -> true)
.defaultIfEmpty(false);
}
}