164 lines
5.2 KiB
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);
|
|
}
|
|
}
|