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

244 lines
7.7 KiB
Java
Raw Normal View History

package it.tdlight.utils;
2021-01-22 17:31:09 +01:00
import io.reactivex.Completable;
2021-01-23 18:49:21 +01:00
import io.reactivex.Flowable;
2021-01-22 17:31:09 +01:00
import io.reactivex.Maybe;
2021-01-23 18:49:21 +01:00
import io.reactivex.Observable;
2021-01-22 17:31:09 +01:00
import io.reactivex.Single;
import io.vertx.core.AsyncResult;
2021-01-22 17:31:09 +01:00
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
2021-01-25 16:06:05 +01:00
import io.vertx.reactivex.core.eventbus.Message;
import io.vertx.reactivex.core.eventbus.MessageConsumer;
2021-01-23 18:49:21 +01:00
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;
2021-06-06 02:24:46 +02:00
import it.tdlight.jni.TdApi.Chat;
import it.tdlight.jni.TdApi.Object;
import it.tdlight.tdlibsession.td.TdError;
import it.tdlight.tdlibsession.td.TdResult;
2021-01-23 18:49:21 +01:00
import java.time.Duration;
import java.util.Objects;
2021-06-01 17:08:59 +02:00
import java.util.Optional;
2021-01-23 18:49:21 +01:00
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
2021-01-23 18:49:21 +01:00
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;
2021-01-23 18:49:21 +01:00
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
2021-06-06 02:24:46 +02:00
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
2021-03-31 12:02:49 +02:00
import org.warp.commonutils.concurrency.future.CompletableFutureUtils;
2021-08-05 21:28:57 +02:00
import org.warp.commonutils.functional.IOConsumer;
2021-02-20 21:25:11 +01:00
import org.warp.commonutils.log.Logger;
import org.warp.commonutils.log.LoggerFactory;
import reactor.core.CoreSubscriber;
2021-01-23 18:49:21 +01:00
import reactor.core.publisher.Flux;
2021-03-31 12:02:49 +02:00
import reactor.core.publisher.FluxSink.OverflowStrategy;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;
2021-01-23 18:49:21 +01:00
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;
2021-01-26 16:29:45 +01:00
import reactor.core.scheduler.Scheduler;
2021-01-23 18:49:21 +01:00
import reactor.core.scheduler.Schedulers;
import reactor.util.concurrent.Queues;
import reactor.util.context.Context;
public class MonoUtils {
2020-10-17 01:53:14 +02:00
private static final Logger logger = LoggerFactory.getLogger(MonoUtils.class);
2021-02-10 18:16:15 +01:00
public static <T> Mono<T> notImplemented() {
return Mono.fromCallable(() -> {
throw new UnsupportedOperationException("Method not implemented");
});
}
2021-01-23 18:49:21 +01:00
public static <T> Mono<T> fromBlockingMaybe(Callable<T> callable) {
2021-01-26 03:46:20 +01:00
return Mono.fromCallable(callable).subscribeOn(Schedulers.boundedElastic());
2021-01-23 18:49:21 +01:00
}
2021-01-26 19:22:55 +01:00
public static Mono<Void> fromBlockingEmpty(EmptyCallable callable) {
return Mono.<Void>fromCallable(() -> {
callable.call();
return null;
}).subscribeOn(Schedulers.boundedElastic());
}
2021-01-23 18:49:21 +01:00
public static <T> Mono<T> fromBlockingSingle(Callable<T> callable) {
return fromBlockingMaybe(callable).single();
}
public static <R extends TdApi.Object> void orElseThrowFuture(TdResult<R> value, SynchronousSink<CompletableFuture<R>> sink) {
if (value.succeeded()) {
sink.next(CompletableFuture.completedFuture(value.result()));
} else {
sink.next(CompletableFuture.failedFuture(new TdError(value.cause().code, value.cause().message)));
}
}
public static <R extends TdApi.Object> Mono<R> orElseThrow(TdResult<R> value) {
if (value.succeeded()) {
return Mono.just(value.result());
} else {
return Mono.error(new TdError(value.cause().code, value.cause().message));
}
}
2020-10-14 15:14:54 +02:00
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));
}
});
}
2020-10-17 01:53:14 +02:00
public static <T extends TdApi.Object> Mono<Void> thenOrLogSkipError(Mono<TdResult<T>> optionalMono) {
return optionalMono.handle((optional, sink) -> {
if (optional.failed()) {
logger.error("Received TDLib error: {}", optional.cause());
}
sink.complete();
});
}
2020-10-20 02:13:58 +02:00
public static <T extends TdApi.Object> Mono<T> orElseLogSkipError(TdResult<T> optional) {
if (optional.failed()) {
logger.error("Received TDLib error: {}", optional.cause());
return Mono.empty();
}
return Mono.just(optional.result());
}
2020-10-17 01:53:14 +02:00
public static <T extends TdApi.Object> Mono<Void> thenOrLogRepeatError(Supplier<? extends Mono<TdResult<T>>> optionalMono) {
return Mono.defer(() -> optionalMono.get().handle((TdResult<T> optional, SynchronousSink<Void> sink) -> {
if (optional.succeeded()) {
sink.complete();
} else {
logger.error("Received TDLib error: {}", optional.cause());
sink.error(new TdError(optional.cause().code, optional.cause().message));
}
})).retry();
}
2021-01-22 17:31:09 +01:00
public static <T> Mono<T> toMono(Future<T> future) {
2021-07-01 20:08:57 +02:00
return Mono.create(sink -> future.onComplete(result -> {
2021-01-22 17:31:09 +01:00
if (result.succeeded()) {
sink.success(result.result());
} else {
sink.error(result.cause());
}
}));
}
@NotNull
2021-01-22 17:31:09 +01:00
public static <T> Mono<T> toMono(Single<T> single) {
2021-01-26 03:46:20 +01:00
return Mono.from(single.toFlowable());
2021-01-22 17:31:09 +01:00
}
@NotNull
2021-01-22 17:31:09 +01:00
public static <T> Mono<T> toMono(Maybe<T> single) {
2021-01-26 03:46:20 +01:00
return Mono.from(single.toFlowable());
2021-01-22 17:31:09 +01:00
}
@NotNull
2021-01-22 17:31:09 +01:00
public static <T> Mono<T> toMono(Completable completable) {
2021-01-26 03:46:20 +01:00
return Mono.from(completable.toFlowable());
2021-01-22 17:31:09 +01:00
}
public static <T> Completable toCompletable(Mono<T> s) {
return Completable.fromPublisher(s);
}
2021-01-23 18:49:21 +01:00
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> Mono<T> castVoid(Mono<Void> mono) {
return (Mono) mono;
}
2021-03-31 12:02:49 +02:00
public static <T> Flux<T> fromMessageConsumer(Mono<Void> onRegistered, MessageConsumer<T> messageConsumer) {
return fromReplyableMessageConsumer(onRegistered, messageConsumer).map(Message::body);
2021-01-26 19:22:55 +01:00
}
2021-03-31 12:02:49 +02:00
public static <T> Flux<Message<T>> fromReplyableMessageConsumer(Mono<Void> onRegistered,
MessageConsumer<T> messageConsumer) {
Mono<Void> endMono = Mono.create(sink -> {
AtomicBoolean alreadyRequested = new AtomicBoolean();
sink.onRequest(n -> {
if (n > 0 && alreadyRequested.compareAndSet(false, true)) {
messageConsumer.endHandler(e -> sink.success());
}
2021-01-26 16:29:45 +01:00
});
2021-03-31 12:02:49 +02:00
});
Mono<MessageConsumer<T>> registrationCompletionMono = Mono
.fromRunnable(() -> logger.trace("Waiting for consumer registration completion..."))
.<Void>then(messageConsumer.rxCompletionHandler().as(MonoUtils::toMono))
.doOnSuccess(s -> logger.trace("Consumer registered"))
.then(onRegistered)
.thenReturn(messageConsumer);
messageConsumer.handler(s -> {
throw new IllegalStateException("Subscriber still didn't request any value!");
});
Flux<Message<T>> dataFlux = Flux
.push(sink -> sink.onRequest(n -> messageConsumer.handler(sink::next)), OverflowStrategy.ERROR);
Mono<Void> disposeMono = messageConsumer
.rxUnregister()
.as(MonoUtils::<Message<T>>toMono)
.doOnSuccess(s -> logger.trace("Unregistered message consumer"))
.then();
return Flux
.usingWhen(registrationCompletionMono, msgCons -> dataFlux, msgCons -> disposeMono)
.takeUntilOther(endMono);
2021-01-26 16:29:45 +01:00
}
2021-03-02 12:01:13 +01:00
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
);
}
2021-06-01 17:08:59 +02:00
public static <R> Mono<Optional<R>> toOptional(Mono<R> mono) {
return mono.map(Optional::of).defaultIfEmpty(Optional.empty());
}
2021-06-06 02:24:46 +02:00
public static <T> Mono<Boolean> isSet(Mono<T> mono) {
return mono
.map(res -> true)
.defaultIfEmpty(false);
}
2021-08-05 21:28:57 +02:00
@FunctionalInterface
public interface VoidCallable {
void call() throws Exception;
}
public static Mono<?> fromVoidCallable(VoidCallable callable) {
return Mono.fromCallable(() -> {
callable.call();
return null;
});
}
}