2020-10-14 01:38:44 +02:00
|
|
|
package it.tdlight.tdlibsession.td.middle.server;
|
|
|
|
|
|
|
|
import static it.tdlight.tdlibsession.td.middle.client.AsyncTdMiddleEventBusClient.OUTPUT_REQUESTS;
|
|
|
|
|
|
|
|
import io.vertx.core.AbstractVerticle;
|
|
|
|
import io.vertx.core.AsyncResult;
|
2020-10-28 12:04:42 +01:00
|
|
|
import io.vertx.core.Future;
|
|
|
|
import io.vertx.core.Handler;
|
2020-10-14 01:38:44 +02:00
|
|
|
import io.vertx.core.Promise;
|
|
|
|
import io.vertx.core.eventbus.Message;
|
2020-10-28 12:04:42 +01:00
|
|
|
import io.vertx.core.eventbus.MessageConsumer;
|
2020-10-14 01:38:44 +02:00
|
|
|
import it.tdlight.common.ConstructorDetector;
|
2020-10-14 15:14:54 +02:00
|
|
|
import it.tdlight.jni.TdApi;
|
2020-10-14 01:38:44 +02:00
|
|
|
import it.tdlight.jni.TdApi.AuthorizationStateClosed;
|
|
|
|
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
|
|
|
|
import it.tdlight.tdlibsession.td.TdResult;
|
|
|
|
import it.tdlight.tdlibsession.td.TdResultMessage;
|
|
|
|
import it.tdlight.tdlibsession.td.direct.AsyncTdDirectImpl;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.ExecuteObject;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.TdClusterManager;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.TdExecuteObjectMessageCodec;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.TdMessageCodec;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.TdOptListMessageCodec;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.TdOptionalList;
|
|
|
|
import it.tdlight.tdlibsession.td.middle.TdResultMessageCodec;
|
|
|
|
import it.tdlight.utils.MonoUtils;
|
|
|
|
import java.time.Duration;
|
2020-10-22 04:45:28 +02:00
|
|
|
import java.util.ArrayList;
|
2020-10-14 01:38:44 +02:00
|
|
|
import java.util.Collections;
|
2020-10-22 04:55:58 +02:00
|
|
|
import java.util.List;
|
2020-10-28 12:04:42 +01:00
|
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
2020-10-22 22:01:05 +02:00
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
2020-10-14 01:38:44 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
2020-10-28 12:04:42 +01:00
|
|
|
import java.util.function.Consumer;
|
2020-10-14 01:38:44 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
import reactor.core.publisher.ReplayProcessor;
|
2020-10-22 22:01:05 +02:00
|
|
|
import reactor.core.scheduler.Scheduler;
|
|
|
|
import reactor.core.scheduler.Schedulers;
|
2020-10-14 01:38:44 +02:00
|
|
|
|
|
|
|
public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
|
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(AsyncTdMiddleEventBusServer.class);
|
2020-10-28 12:04:42 +01:00
|
|
|
|
2020-10-14 01:38:44 +02:00
|
|
|
private static final byte[] EMPTY = new byte[0];
|
|
|
|
// todo: restore duration to 2 seconds instead of 10 millis, when the bug of tdlight double queue wait is fixed
|
|
|
|
public static final Duration WAIT_DURATION = Duration.ofSeconds(1);// Duration.ofMillis(10);
|
2020-10-22 22:01:05 +02:00
|
|
|
// If you enable this the poll will wait up to 100 additional milliseconds between each poll, if the server is remote
|
|
|
|
private static final boolean ENABLE_MINIMUM_POLL_WAIT_INTERVAL = false;
|
2020-10-14 01:38:44 +02:00
|
|
|
|
|
|
|
private final TdClusterManager cluster;
|
|
|
|
|
|
|
|
private String botAlias;
|
|
|
|
private String botAddress;
|
|
|
|
private boolean local;
|
|
|
|
|
|
|
|
protected final ReplayProcessor<Boolean> tdClosed = ReplayProcessor.cacheLastOrDefault(false);
|
|
|
|
protected AsyncTdDirectImpl td;
|
2020-10-28 12:04:42 +01:00
|
|
|
protected final LinkedBlockingQueue<AsyncResult<TdResult<TdApi.Object>>> queue = new LinkedBlockingQueue<>();
|
2020-10-22 22:01:05 +02:00
|
|
|
private final Scheduler tdSrvPoll;
|
2020-10-28 12:04:42 +01:00
|
|
|
private List<Consumer<Promise<Void>>> onBeforeStopListeners = new CopyOnWriteArrayList<>();
|
|
|
|
private List<Consumer<Promise<Void>>> onAfterStopListeners = new CopyOnWriteArrayList<>();
|
|
|
|
private MessageConsumer<?> startConsumer;
|
|
|
|
private MessageConsumer<byte[]> isWorkingConsumer;
|
|
|
|
private MessageConsumer<byte[]> getNextUpdatesBlockConsumer;
|
|
|
|
private MessageConsumer<ExecuteObject> executeConsumer;
|
2020-10-14 01:38:44 +02:00
|
|
|
|
|
|
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
|
|
public AsyncTdMiddleEventBusServer(TdClusterManager clusterManager) {
|
|
|
|
this.cluster = clusterManager;
|
2020-10-22 22:01:05 +02:00
|
|
|
this.tdSrvPoll = Schedulers.newSingle("TdSrvPoll");
|
2020-10-14 01:38:44 +02:00
|
|
|
if (cluster.registerDefaultCodec(TdOptionalList.class, new TdOptListMessageCodec())) {
|
|
|
|
cluster.registerDefaultCodec(ExecuteObject.class, new TdExecuteObjectMessageCodec());
|
|
|
|
cluster.registerDefaultCodec(TdResultMessage.class, new TdResultMessageCodec());
|
|
|
|
for (Class<?> value : ConstructorDetector.getTDConstructorsUnsafe().values()) {
|
|
|
|
cluster.registerDefaultCodec(value, new TdMessageCodec(value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void start(Promise<Void> startPromise) {
|
|
|
|
var botAddress = config().getString("botAddress");
|
|
|
|
if (botAddress == null || botAddress.isEmpty()) {
|
|
|
|
throw new IllegalArgumentException("botAddress is not set!");
|
|
|
|
}
|
|
|
|
this.botAddress = botAddress;
|
|
|
|
var botAlias = config().getString("botAlias");
|
|
|
|
if (botAlias == null || botAlias.isEmpty()) {
|
|
|
|
throw new IllegalArgumentException("botAlias is not set!");
|
|
|
|
}
|
|
|
|
this.botAlias = botAlias;
|
|
|
|
var local = config().getBoolean("local");
|
|
|
|
if (local == null) {
|
|
|
|
throw new IllegalArgumentException("local is not set!");
|
|
|
|
}
|
|
|
|
this.local = local;
|
|
|
|
this.td = new AsyncTdDirectImpl(botAlias);
|
|
|
|
|
|
|
|
AtomicBoolean alreadyDeployed = new AtomicBoolean(false);
|
2020-10-28 12:04:42 +01:00
|
|
|
this.startConsumer = cluster.getEventBus().consumer(botAddress + ".start", (Message<byte[]> msg) -> {
|
2020-10-14 01:38:44 +02:00
|
|
|
if (alreadyDeployed.compareAndSet(false, true)) {
|
|
|
|
td.initializeClient()
|
|
|
|
.then(this.listen())
|
|
|
|
.then(this.pipe())
|
|
|
|
.then(Mono.<Void>create(registrationSink -> {
|
|
|
|
|
2020-10-28 12:04:42 +01:00
|
|
|
this.isWorkingConsumer = cluster.getEventBus().consumer(botAddress + ".isWorking", (Message<byte[]> workingMsg) -> {
|
2020-10-14 01:38:44 +02:00
|
|
|
workingMsg.reply(EMPTY, cluster.newDeliveryOpts().setLocalOnly(local));
|
2020-10-28 12:04:42 +01:00
|
|
|
});
|
|
|
|
this.isWorkingConsumer.completionHandler(MonoUtils.toHandler(registrationSink));
|
2020-10-14 01:38:44 +02:00
|
|
|
|
|
|
|
}))
|
|
|
|
.subscribe(v -> {}, ex -> {
|
|
|
|
logger.info(botAddress + " server deployed and started. succeeded: false");
|
|
|
|
logger.error(ex.getLocalizedMessage(), ex);
|
|
|
|
msg.fail(500, ex.getLocalizedMessage());
|
|
|
|
}, () -> {
|
|
|
|
logger.info(botAddress + " server deployed and started. succeeded: true");
|
|
|
|
msg.reply(EMPTY);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
msg.reply(EMPTY);
|
|
|
|
}
|
2020-10-28 12:04:42 +01:00
|
|
|
});
|
|
|
|
startConsumer.completionHandler(h -> {
|
2020-10-14 01:38:44 +02:00
|
|
|
logger.info(botAddress + " server deployed. succeeded: " + h.succeeded());
|
|
|
|
if (h.succeeded()) {
|
|
|
|
startPromise.complete(h.result());
|
|
|
|
} else {
|
|
|
|
startPromise.fail(h.cause());
|
|
|
|
}
|
|
|
|
});
|
2020-10-28 12:04:42 +01:00
|
|
|
|
|
|
|
logger.debug("Sending " + botAddress + ".readyToStart");
|
|
|
|
cluster.getEventBus().send(botAddress + ".readyToStart", EMPTY, cluster.newDeliveryOpts().setSendTimeout(10000));
|
|
|
|
|
|
|
|
var clientDeadCheckThread = new Thread(() -> {
|
|
|
|
Throwable ex = null;
|
|
|
|
try {
|
|
|
|
while (!Thread.interrupted()) {
|
|
|
|
Thread.sleep(5000);
|
|
|
|
Promise<Void> promise = Promise.promise();
|
|
|
|
cluster
|
|
|
|
.getEventBus()
|
|
|
|
.request(botAddress + ".readyToStart",
|
|
|
|
EMPTY,
|
|
|
|
cluster.newDeliveryOpts().setSendTimeout(10000),
|
|
|
|
r -> promise.handle(r.mapEmpty())
|
|
|
|
);
|
|
|
|
promise.future().toCompletionStage().toCompletableFuture().join();
|
|
|
|
}
|
|
|
|
} catch (Throwable e) {
|
|
|
|
ex = e;
|
|
|
|
}
|
|
|
|
var closed = tdClosed.blockFirst();
|
|
|
|
if (closed == null || !closed) {
|
|
|
|
if (ex != null && !ex.getMessage().contains("NO_HANDLERS")) {
|
|
|
|
logger.error(ex.getLocalizedMessage(), ex);
|
|
|
|
}
|
|
|
|
logger.error("TDLib client disconnected unexpectedly! Closing the server...");
|
|
|
|
undeploy(() -> {});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
clientDeadCheckThread.setName("Client " + botAddress + " dead check");
|
|
|
|
clientDeadCheckThread.setDaemon(true);
|
|
|
|
clientDeadCheckThread.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onBeforeStop(Consumer<Promise<Void>> r) {
|
|
|
|
this.onBeforeStopListeners.add(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onAfterStop(Consumer<Promise<Void>> r) {
|
|
|
|
this.onAfterStopListeners.add(r);
|
2020-10-14 01:38:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void stop(Promise<Void> stopPromise) {
|
2020-10-28 12:04:42 +01:00
|
|
|
runAll(onBeforeStopListeners, onBeforeStopHandler -> {
|
|
|
|
if (onBeforeStopHandler.failed()) {
|
|
|
|
logger.error("A beforeStop listener failed: "+ onBeforeStopHandler.cause());
|
|
|
|
}
|
|
|
|
|
|
|
|
td.destroyClient().onErrorResume(ex -> {
|
|
|
|
logger.error("Can't destroy client", ex);
|
|
|
|
return Mono.empty();
|
|
|
|
}).doOnError(err -> {
|
|
|
|
logger.error("TdMiddle verticle failed during stop", err);
|
|
|
|
}).then(Mono.create(sink -> {
|
|
|
|
this.isWorkingConsumer.unregister(result -> {
|
|
|
|
if (result.failed()) {
|
|
|
|
logger.error("Can't unregister consumer", result.cause());
|
|
|
|
}
|
|
|
|
this.startConsumer.unregister(result2 -> {
|
|
|
|
if (result2.failed()) {
|
|
|
|
logger.error("Can't unregister consumer", result2.cause());
|
|
|
|
}
|
|
|
|
|
|
|
|
tdClosed.onNext(true);
|
|
|
|
|
|
|
|
this.getNextUpdatesBlockConsumer.unregister(result3 -> {
|
|
|
|
if (result3.failed()) {
|
|
|
|
logger.error("Can't unregister consumer", result3.cause());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.executeConsumer.unregister(result4 -> {
|
|
|
|
if (result4.failed()) {
|
|
|
|
logger.error("Can't unregister consumer", result4.cause());
|
|
|
|
}
|
|
|
|
|
|
|
|
sink.success();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})).doFinally(signalType -> {
|
|
|
|
logger.info("TdMiddle verticle \"" + botAddress + "\" stopped");
|
|
|
|
|
|
|
|
runAll(onAfterStopListeners, onAfterStopHandler -> {
|
|
|
|
if (onAfterStopHandler.failed()) {
|
|
|
|
logger.error("An afterStop listener failed: " + onAfterStopHandler.cause());
|
|
|
|
}
|
|
|
|
|
|
|
|
stopPromise.complete();
|
|
|
|
});
|
|
|
|
}).subscribe();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void runAll(List<Consumer<Promise<Void>>> actions, Handler<AsyncResult<Void>> resultHandler) {
|
|
|
|
if (actions.isEmpty()) {
|
|
|
|
resultHandler.handle(Future.succeededFuture());
|
|
|
|
} else {
|
|
|
|
var firstAction = actions.remove(0);
|
|
|
|
Promise<Void> promise = Promise.promise();
|
|
|
|
firstAction.accept(promise);
|
|
|
|
promise.future().onComplete(handler -> {
|
|
|
|
if (handler.succeeded()) {
|
|
|
|
runAll(new ArrayList<>(actions), resultHandler);
|
|
|
|
} else {
|
|
|
|
resultHandler.handle(Future.failedFuture(handler.cause()));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-10-14 01:38:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private Mono<Void> listen() {
|
|
|
|
return Mono.<Void>create(registrationSink -> {
|
2020-10-28 12:04:42 +01:00
|
|
|
this.getNextUpdatesBlockConsumer = cluster.getEventBus().consumer(botAddress + ".getNextUpdatesBlock", (Message<byte[]> msg) -> {
|
2020-10-22 22:01:05 +02:00
|
|
|
// Run only if tdlib is not closed
|
|
|
|
Mono.from(tdClosed).single().filter(tdClosedVal -> !tdClosedVal)
|
|
|
|
// Get a list of updates
|
|
|
|
.flatMap(_v -> Mono
|
2020-10-28 12:04:42 +01:00
|
|
|
.<List<AsyncResult<TdResult<TdApi.Object>>>>fromSupplier(() -> {
|
2020-10-22 22:01:05 +02:00
|
|
|
// When a request is asked, read up to 1000 available updates in the queue
|
|
|
|
long requestTime = System.currentTimeMillis();
|
2020-10-28 12:04:42 +01:00
|
|
|
ArrayList<AsyncResult<TdResult<TdApi.Object>>> updatesBatch = new ArrayList<>();
|
2020-10-22 22:01:05 +02:00
|
|
|
try {
|
|
|
|
// Block until an update is found or 5 seconds passed
|
|
|
|
var item = queue.poll(5, TimeUnit.SECONDS);
|
|
|
|
if (item != null) {
|
|
|
|
updatesBatch.add(item);
|
|
|
|
queue.drainTo(updatesBatch, local ? 999 : 998);
|
|
|
|
|
|
|
|
if (ENABLE_MINIMUM_POLL_WAIT_INTERVAL) {
|
|
|
|
if (!local) {
|
|
|
|
var item2 = queue.poll(100, TimeUnit.MILLISECONDS);
|
|
|
|
if (item2 != null) {
|
|
|
|
updatesBatch.add(item2);
|
|
|
|
queue.drainTo(updatesBatch, Math.max(0, 1000 - updatesBatch.size()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
// polling cancelled, expected sometimes
|
|
|
|
}
|
|
|
|
// Return the updates found, can be an empty list
|
|
|
|
return updatesBatch;
|
|
|
|
})
|
|
|
|
// Subscribe on td server poll scheduler
|
|
|
|
.subscribeOn(tdSrvPoll)
|
|
|
|
// Filter out empty updates lists
|
|
|
|
.filter(updates -> !updates.isEmpty())
|
|
|
|
.repeatWhen(s -> s
|
|
|
|
// Take until an update is received
|
|
|
|
.takeWhile(n -> n == 0)
|
|
|
|
// Take until tdClosed is true
|
|
|
|
.takeUntilOther(tdClosed.filter(closed -> closed).take(1).single())
|
|
|
|
)
|
|
|
|
// Take only one update list
|
|
|
|
.take(1)
|
|
|
|
// If 5 seconds pass, return a list with 0 updates
|
|
|
|
.timeout(Duration.ofSeconds(5), Mono.just(List.of()))
|
|
|
|
// Return 1 list or 0 lists
|
|
|
|
.singleOrEmpty()
|
|
|
|
)
|
2020-10-22 04:45:28 +02:00
|
|
|
.flatMap(receivedList -> {
|
|
|
|
return Flux.fromIterable(receivedList).flatMap(result -> {
|
|
|
|
if (result.succeeded()) {
|
|
|
|
var received = result.result();
|
|
|
|
if (OUTPUT_REQUESTS) {
|
|
|
|
System.out.println("<=: " + received
|
|
|
|
.toString()
|
|
|
|
.replace("\n", " ")
|
|
|
|
.replace("\t", "")
|
|
|
|
.replace(" ", "")
|
|
|
|
.replace(" = ", "="));
|
|
|
|
}
|
|
|
|
return Mono.create(sink -> {
|
|
|
|
if (received.succeeded() && received.result().getConstructor() == UpdateAuthorizationState.CONSTRUCTOR) {
|
|
|
|
var authState = (UpdateAuthorizationState) received.result();
|
|
|
|
if (authState.authorizationState.getConstructor() == AuthorizationStateClosed.CONSTRUCTOR) {
|
2020-10-28 12:04:42 +01:00
|
|
|
undeploy(sink::success);
|
2020-10-22 04:45:28 +02:00
|
|
|
} else {
|
2020-10-14 01:38:44 +02:00
|
|
|
sink.success();
|
2020-10-22 04:45:28 +02:00
|
|
|
}
|
2020-10-14 01:38:44 +02:00
|
|
|
} else {
|
|
|
|
sink.success();
|
|
|
|
}
|
2020-10-28 12:04:42 +01:00
|
|
|
}).then(Mono.<TdResult<TdApi.Object>>create(sink -> {
|
2020-10-22 04:45:28 +02:00
|
|
|
sink.success(received);
|
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
logger.error("Received an error update", result.cause());
|
|
|
|
return Mono.empty();
|
|
|
|
}
|
|
|
|
}).collectList().map(list -> new TdOptionalList(true, list));
|
|
|
|
})
|
2020-10-14 01:38:44 +02:00
|
|
|
.defaultIfEmpty(new TdOptionalList(false, Collections.emptyList()))
|
2020-10-22 22:01:05 +02:00
|
|
|
.subscribeOn(tdSrvPoll)
|
2020-10-14 01:38:44 +02:00
|
|
|
.subscribe(v -> {
|
|
|
|
msg.reply(v);
|
|
|
|
}, ex -> {
|
|
|
|
logger.error("Error when processing a 'receiveUpdates' request", ex);
|
|
|
|
msg.fail(500, ex.getLocalizedMessage());
|
|
|
|
}, () -> {});
|
2020-10-28 12:04:42 +01:00
|
|
|
});
|
|
|
|
getNextUpdatesBlockConsumer.completionHandler(MonoUtils.toHandler(registrationSink));
|
2020-10-14 01:38:44 +02:00
|
|
|
|
|
|
|
}).then(Mono.<Void>create(registrationSink -> {
|
|
|
|
|
2020-10-28 12:04:42 +01:00
|
|
|
this.executeConsumer = cluster.getEventBus().<ExecuteObject>consumer(botAddress + ".execute", (Message<ExecuteObject> msg) -> {
|
2020-10-14 01:38:44 +02:00
|
|
|
try {
|
|
|
|
if (OUTPUT_REQUESTS) {
|
|
|
|
System.out.println(":=> " + msg
|
|
|
|
.body()
|
|
|
|
.getRequest()
|
|
|
|
.toString()
|
|
|
|
.replace("\n", " ")
|
|
|
|
.replace("\t", "")
|
|
|
|
.replace(" ", "")
|
|
|
|
.replace(" = ", "="));
|
|
|
|
}
|
2020-10-14 15:14:54 +02:00
|
|
|
td
|
|
|
|
.execute(msg.body().getRequest(), msg.body().isExecuteDirectly())
|
|
|
|
.switchIfEmpty(Mono.fromSupplier(() -> {
|
|
|
|
return TdResult.failed(new TdApi.Error(500, "Received null response"));
|
|
|
|
}))
|
2020-10-14 20:04:23 +02:00
|
|
|
.handle((response, sink) -> {
|
|
|
|
try {
|
|
|
|
msg.reply(new TdResultMessage(response.result(), response.cause()),
|
|
|
|
cluster.newDeliveryOpts().setLocalOnly(local)
|
|
|
|
);
|
|
|
|
sink.next(response);
|
|
|
|
} catch (Exception ex) {
|
|
|
|
sink.error(ex);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.subscribe(response -> {}, ex -> {
|
2020-10-14 15:14:54 +02:00
|
|
|
logger.error("Error when processing a request", ex);
|
|
|
|
msg.fail(500, ex.getLocalizedMessage());
|
|
|
|
});
|
2020-10-14 01:38:44 +02:00
|
|
|
} catch (ClassCastException ex) {
|
|
|
|
logger.error("Error when deserializing a request", ex);
|
2020-10-14 15:14:54 +02:00
|
|
|
msg.fail(500, ex.getMessage());
|
2020-10-14 01:38:44 +02:00
|
|
|
}
|
2020-10-28 12:04:42 +01:00
|
|
|
});
|
|
|
|
executeConsumer.completionHandler(MonoUtils.toHandler(registrationSink));
|
2020-10-14 01:38:44 +02:00
|
|
|
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2020-10-28 12:04:42 +01:00
|
|
|
private void undeploy(Runnable whenUndeployed) {
|
|
|
|
vertx.undeploy(deploymentID(), undeployed -> {
|
|
|
|
if (undeployed.failed()) {
|
|
|
|
logger.error("Error when undeploying td verticle", undeployed.cause());
|
|
|
|
}
|
|
|
|
whenUndeployed.run();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-10-14 01:38:44 +02:00
|
|
|
private Mono<Void> pipe() {
|
|
|
|
return Mono.fromCallable(() -> {
|
2020-10-22 04:45:28 +02:00
|
|
|
td
|
2020-10-14 01:38:44 +02:00
|
|
|
.getUpdates(WAIT_DURATION, 1000)
|
2020-10-22 04:45:28 +02:00
|
|
|
.bufferTimeout(1000, local ? Duration.ofMillis(1) : Duration.ofMillis(100))
|
|
|
|
.subscribe(nextItems -> {
|
|
|
|
queue.addAll(nextItems);
|
|
|
|
});
|
2020-10-14 01:38:44 +02:00
|
|
|
return (Void) null;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|