Use atomic references
This commit is contained in:
parent
cd48a587b7
commit
7c9f3e2879
@ -20,6 +20,7 @@ import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -44,10 +45,6 @@ public class TDLibRemoteClient implements AutoCloseable {
|
||||
private final int port;
|
||||
private final Set<String> membersAddresses;
|
||||
private final One<TdClusterManager> clusterManager = Sinks.one();
|
||||
/**
|
||||
* Statistic about active deployments count
|
||||
*/
|
||||
private final AtomicInteger statsActiveDeployments = new AtomicInteger();
|
||||
|
||||
public static boolean runningFromIntelliJ() {
|
||||
return System.getProperty("java.class.path").contains("idea_rt.jar")
|
||||
@ -68,6 +65,7 @@ public class TDLibRemoteClient implements AutoCloseable {
|
||||
this.membersAddresses = membersAddresses;
|
||||
|
||||
if (enableAsyncStacktraces && !runningFromIntelliJ()) {
|
||||
//noinspection ReactorAutomaticDebugger
|
||||
ReactorDebugAgent.init();
|
||||
}
|
||||
if (enableAsyncStacktraces && enableFullAsyncStacktraces) {
|
||||
@ -106,7 +104,10 @@ public class TDLibRemoteClient implements AutoCloseable {
|
||||
boolean enableFullAsyncStacktraces = Boolean.parseBoolean(args[8]);
|
||||
|
||||
var loggerContext = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
|
||||
loggerContext.setConfigLocation(TDLibRemoteClient.class.getResource("/tdlib-session-container-log4j2.xml").toURI());
|
||||
loggerContext.setConfigLocation(Objects
|
||||
.requireNonNull(TDLibRemoteClient.class.getResource("/tdlib-session-container-log4j2.xml"),
|
||||
"tdlib-session-container-log4j2.xml doesn't exist")
|
||||
.toURI());
|
||||
|
||||
var securityInfo = new SecurityInfo(keyStorePath, keyStorePasswordPath, trustStorePath, trustStorePasswordPath);
|
||||
|
||||
@ -124,7 +125,7 @@ public class TDLibRemoteClient implements AutoCloseable {
|
||||
.block();
|
||||
|
||||
// Close vert.x on shutdown
|
||||
var vertx = client.clusterManager.asMono().block().getVertx();
|
||||
var vertx = client.clusterManager.asMono().blockOptional().orElseThrow().getVertx();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> MonoUtils.toMono(vertx.rxClose()).blockOptional()));
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,14 @@ import it.tdlight.utils.MonoUtils;
|
||||
import java.net.ConnectException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import org.warp.commonutils.locks.LockUtils;
|
||||
import org.warp.commonutils.log.Logger;
|
||||
import org.warp.commonutils.log.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
import reactor.core.publisher.Sinks.EmitResult;
|
||||
import reactor.core.publisher.Sinks.Empty;
|
||||
import reactor.core.publisher.Sinks.One;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
@ -130,7 +133,14 @@ public class AsyncTdMiddleEventBusClient implements AsyncTdMiddle {
|
||||
this.local = local;
|
||||
this.logger = LoggerFactory.getLogger(this.botId + " " + botAlias);
|
||||
return MonoUtils
|
||||
.emitValue(this.binlog, binlog)
|
||||
.fromBlockingEmpty(() -> {
|
||||
EmitResult result;
|
||||
while ((result = this.binlog.tryEmitValue(binlog)) == EmitResult.FAIL_NON_SERIALIZED) {
|
||||
// 10ms
|
||||
LockSupport.parkNanos(10000000);
|
||||
}
|
||||
result.orThrow();
|
||||
})
|
||||
.then(binlog.getLastModifiedTime())
|
||||
.zipWith(binlog.readFully().map(Buffer::getDelegate))
|
||||
.single()
|
||||
@ -173,11 +183,15 @@ public class AsyncTdMiddleEventBusClient implements AsyncTdMiddle {
|
||||
})
|
||||
.flatMap(msg -> Mono.fromCallable(msg::body).subscribeOn(Schedulers.boundedElastic()))
|
||||
.repeatWhen(l -> l.delayElements(Duration.ofSeconds(10)).takeWhile(x -> true))
|
||||
.takeUntilOther(Mono.firstWithSignal(this.updatesStreamEnd.asMono().doOnTerminate(() -> {
|
||||
logger.trace("About to kill pinger because updates stream ended");
|
||||
}), this.crash.asMono().onErrorResume(ex -> Mono.empty()).doOnTerminate(() -> {
|
||||
logger.trace("About to kill pinger because it has seen a crash signal");
|
||||
})))
|
||||
.takeUntilOther(Mono.firstWithSignal(
|
||||
this.updatesStreamEnd
|
||||
.asMono()
|
||||
.doOnTerminate(() -> logger.trace("About to kill pinger because updates stream ended")),
|
||||
this.crash
|
||||
.asMono()
|
||||
.onErrorResume(ex -> Mono.empty())
|
||||
.doOnTerminate(() -> logger.trace("About to kill pinger because it has seen a crash signal"))
|
||||
))
|
||||
.doOnNext(s -> logger.trace("PING"))
|
||||
.then()
|
||||
.onErrorResume(ex -> {
|
||||
@ -185,7 +199,12 @@ public class AsyncTdMiddleEventBusClient implements AsyncTdMiddle {
|
||||
return Mono.empty();
|
||||
})
|
||||
.doOnNext(s -> logger.debug("END PING"))
|
||||
.then(MonoUtils.emitEmpty(this.pingFail))
|
||||
.then(MonoUtils.fromBlockingEmpty(() -> {
|
||||
while (this.pingFail.tryEmitEmpty() == EmitResult.FAIL_NON_SERIALIZED) {
|
||||
// 10ms
|
||||
LockSupport.parkNanos(10000000);
|
||||
}
|
||||
}))
|
||||
.subscribeOn(Schedulers.parallel())
|
||||
.subscribe();
|
||||
}
|
||||
@ -207,7 +226,14 @@ public class AsyncTdMiddleEventBusClient implements AsyncTdMiddle {
|
||||
// Return when the registration of all the consumers has been done across the cluster
|
||||
return Mono
|
||||
.fromRunnable(() -> logger.trace("Emitting updates flux to sink"))
|
||||
.then(MonoUtils.emitValue(updates, updateConsumer))
|
||||
.then(MonoUtils.fromBlockingEmpty(() -> {
|
||||
EmitResult result;
|
||||
while ((result = this.updates.tryEmitValue(updateConsumer)) == EmitResult.FAIL_NON_SERIALIZED) {
|
||||
// 10ms
|
||||
LockSupport.parkNanos(10000000);
|
||||
}
|
||||
result.orThrow();
|
||||
}))
|
||||
.doOnSuccess(s -> logger.trace("Emitted updates flux to sink"))
|
||||
.doOnSuccess(s -> logger.trace("Waiting to register update consumer across the cluster"))
|
||||
.doOnSuccess(s -> logger.trace("Registered update consumer across the cluster"));
|
||||
@ -250,7 +276,14 @@ public class AsyncTdMiddleEventBusClient implements AsyncTdMiddle {
|
||||
var ex = new ConnectException("Server did not respond to ping");
|
||||
ex.setStackTrace(new StackTraceElement[0]);
|
||||
throw ex;
|
||||
}).onErrorResume(ex -> MonoUtils.emitError(crash, ex)))
|
||||
})).onErrorResume(ex -> MonoUtils.fromBlockingSingle(() -> {
|
||||
EmitResult result;
|
||||
while ((result = this.crash.tryEmitError(ex)) == EmitResult.FAIL_NON_SERIALIZED) {
|
||||
// 10ms
|
||||
LockSupport.parkNanos(10000000);
|
||||
}
|
||||
return result;
|
||||
}))
|
||||
.takeUntilOther(Mono
|
||||
.firstWithSignal(crash.asMono(), authStateClosing.asMono())
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
@ -285,23 +318,21 @@ public class AsyncTdMiddleEventBusClient implements AsyncTdMiddle {
|
||||
|
||||
private Mono<TdApi.Object> interceptUpdate(Object update) {
|
||||
logger.trace("Received update {}", update.getClass().getSimpleName());
|
||||
switch (update.getConstructor()) {
|
||||
case TdApi.UpdateAuthorizationState.CONSTRUCTOR:
|
||||
var updateAuthorizationState = (TdApi.UpdateAuthorizationState) update;
|
||||
switch (updateAuthorizationState.authorizationState.getConstructor()) {
|
||||
case TdApi.AuthorizationStateClosing.CONSTRUCTOR:
|
||||
authStateClosing.tryEmitEmpty();
|
||||
break;
|
||||
case TdApi.AuthorizationStateClosed.CONSTRUCTOR:
|
||||
return Mono.fromRunnable(() -> logger.info("Received AuthorizationStateClosed from tdlib"))
|
||||
.then(cluster.getEventBus().<EndSessionMessage>rxRequest(this.botAddress + ".read-binlog", EMPTY).as(MonoUtils::toMono))
|
||||
.flatMap(latestBinlogMsg -> Mono.fromCallable(latestBinlogMsg::body).subscribeOn(Schedulers.parallel()))
|
||||
.doOnNext(latestBinlog -> logger.info("Received binlog from server. Size: " + BinlogUtils.humanReadableByteCountBin(latestBinlog.binlog().length())))
|
||||
.flatMap(latestBinlog -> this.saveBinlog(latestBinlog.binlog()))
|
||||
.doOnSuccess(s -> logger.info("Overwritten binlog from server"))
|
||||
.thenReturn(update);
|
||||
}
|
||||
break;
|
||||
if (update.getConstructor() == TdApi.UpdateAuthorizationState.CONSTRUCTOR) {
|
||||
var updateAuthorizationState = (TdApi.UpdateAuthorizationState) update;
|
||||
switch (updateAuthorizationState.authorizationState.getConstructor()) {
|
||||
case TdApi.AuthorizationStateClosing.CONSTRUCTOR:
|
||||
authStateClosing.tryEmitEmpty();
|
||||
break;
|
||||
case TdApi.AuthorizationStateClosed.CONSTRUCTOR:
|
||||
return Mono.fromRunnable(() -> logger.info("Received AuthorizationStateClosed from tdlib"))
|
||||
.then(cluster.getEventBus().<EndSessionMessage>rxRequest(this.botAddress + ".read-binlog", EMPTY).as(MonoUtils::toMono))
|
||||
.flatMap(latestBinlogMsg -> Mono.fromCallable(latestBinlogMsg::body).subscribeOn(Schedulers.parallel()))
|
||||
.doOnNext(latestBinlog -> logger.info("Received binlog from server. Size: " + BinlogUtils.humanReadableByteCountBin(latestBinlog.binlog().length())))
|
||||
.flatMap(latestBinlog -> this.saveBinlog(latestBinlog.binlog()))
|
||||
.doOnSuccess(s -> logger.info("Overwritten binlog from server"))
|
||||
.thenReturn(update);
|
||||
}
|
||||
}
|
||||
return Mono.just(update);
|
||||
}
|
||||
|
@ -25,17 +25,16 @@ import it.tdlight.tdlibsession.td.middle.TdResultList;
|
||||
import it.tdlight.tdlibsession.td.middle.TdResultListMessageCodec;
|
||||
import it.tdlight.tdlibsession.td.middle.TdResultMessage;
|
||||
import it.tdlight.utils.BinlogUtils;
|
||||
import it.tdlight.utils.BufferTimeOutPublisher;
|
||||
import it.tdlight.utils.MonoUtils;
|
||||
import java.net.ConnectException;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.warp.commonutils.log.Logger;
|
||||
import org.warp.commonutils.log.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
import reactor.core.publisher.Sinks.One;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
@ -51,18 +50,17 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
private final TelegramClientFactory clientFactory;
|
||||
|
||||
// Variables configured by the user at startup
|
||||
private final One<Integer> botId = Sinks.one();
|
||||
private final One<String> botAddress = Sinks.one();
|
||||
private final One<String> botAlias = Sinks.one();
|
||||
private final One<Boolean> local = Sinks.one();
|
||||
private final AtomicReference<Integer> botId = new AtomicReference<>();
|
||||
private final AtomicReference<String> botAddress = new AtomicReference<>();
|
||||
private final AtomicReference<String> botAlias = new AtomicReference<>();
|
||||
|
||||
// Variables configured at startup
|
||||
private final One<AsyncTdDirectImpl> td = Sinks.one();
|
||||
private final One<MessageConsumer<ExecuteObject>> executeConsumer = Sinks.one();
|
||||
private final One<MessageConsumer<byte[]>> readBinlogConsumer = Sinks.one();
|
||||
private final One<MessageConsumer<byte[]>> readyToReceiveConsumer = Sinks.one();
|
||||
private final One<MessageConsumer<byte[]>> pingConsumer = Sinks.one();
|
||||
private final One<Flux<Void>> pipeFlux = Sinks.one();
|
||||
private final AtomicReference<AsyncTdDirectImpl> td = new AtomicReference<>();
|
||||
private final AtomicReference<MessageConsumer<ExecuteObject>> executeConsumer = new AtomicReference<>();
|
||||
private final AtomicReference<MessageConsumer<byte[]>> readBinlogConsumer = new AtomicReference<>();
|
||||
private final AtomicReference<MessageConsumer<byte[]>> readyToReceiveConsumer = new AtomicReference<>();
|
||||
private final AtomicReference<MessageConsumer<byte[]>> pingConsumer = new AtomicReference<>();
|
||||
private final AtomicReference<Flux<Void>> pipeFlux = new AtomicReference<>();
|
||||
|
||||
public AsyncTdMiddleEventBusServer() {
|
||||
this.tdOptions = new AsyncTdDirectOptions(WAIT_DURATION, 100);
|
||||
@ -79,20 +77,14 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
if (botId == null || botId <= 0) {
|
||||
throw new IllegalArgumentException("botId is not set!");
|
||||
}
|
||||
if (this.botId.tryEmitValue(botId).isFailure()) {
|
||||
throw new IllegalStateException("Failed to set botId");
|
||||
}
|
||||
this.botId.set(botId);
|
||||
var botAddress = "bots.bot." + botId;
|
||||
if (this.botAddress.tryEmitValue(botAddress).isFailure()) {
|
||||
throw new IllegalStateException("Failed to set botAddress");
|
||||
}
|
||||
this.botAddress.set(botAddress);
|
||||
var botAlias = config().getString("botAlias");
|
||||
if (botAlias == null || botAlias.isEmpty()) {
|
||||
throw new IllegalArgumentException("botAlias is not set!");
|
||||
}
|
||||
if (this.botAlias.tryEmitValue(botAlias).isFailure()) {
|
||||
throw new IllegalStateException("Failed to set botAlias");
|
||||
}
|
||||
this.botAlias.set(botAlias);
|
||||
var local = config().getBoolean("local");
|
||||
if (local == null) {
|
||||
throw new IllegalArgumentException("local is not set!");
|
||||
@ -103,9 +95,7 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
}
|
||||
|
||||
var td = new AsyncTdDirectImpl(clientFactory, implementationDetails, botAlias);
|
||||
if (this.td.tryEmitValue(td).isFailure()) {
|
||||
throw new IllegalStateException("Failed to set td instance");
|
||||
}
|
||||
this.td.set(td);
|
||||
return new OnSuccessfulStartRequestInfo(td, botAddress, botAlias, botId, local);
|
||||
})
|
||||
.flatMap(r -> onSuccessfulStartRequest(r.td, r.botAddress, r.botAlias, r.botId, r.local))
|
||||
@ -135,25 +125,18 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
boolean local) {
|
||||
return td
|
||||
.initialize()
|
||||
.then(this.pipe(td, botAddress, botAlias, botId, local))
|
||||
.then(this.listen(td, botAddress, botAlias, botId, local))
|
||||
.doOnSuccess(s -> {
|
||||
logger.info("Deploy and start of bot \"" + botAlias + "\": ✅ Succeeded");
|
||||
})
|
||||
.doOnError(ex -> {
|
||||
logger.error("Deploy and start of bot \"" + botAlias + "\": ❌ Failed", ex);
|
||||
});
|
||||
.then(this.pipe(td, botAddress, local))
|
||||
.then(this.listen(td, botAddress, botId, local))
|
||||
.doOnSuccess(s -> logger.info("Deploy and start of bot \"" + botAlias + "\": ✅ Succeeded"))
|
||||
.doOnError(ex -> logger.error("Deploy and start of bot \"" + botAlias + "\": ❌ Failed", ex));
|
||||
}
|
||||
|
||||
private Mono<Void> listen(AsyncTdDirectImpl td, String botAddress, String botAlias, int botId, boolean local) {
|
||||
private Mono<Void> listen(AsyncTdDirectImpl td, String botAddress, int botId, boolean local) {
|
||||
return Mono.<Void>create(registrationSink -> {
|
||||
logger.trace("Preparing listeners");
|
||||
|
||||
MessageConsumer<ExecuteObject> executeConsumer = vertx.eventBus().consumer(botAddress + ".execute");
|
||||
if (this.executeConsumer.tryEmitValue(executeConsumer).isFailure()) {
|
||||
registrationSink.error(new IllegalStateException("Failed to set executeConsumer"));
|
||||
return;
|
||||
}
|
||||
this.executeConsumer.set(executeConsumer);
|
||||
Flux
|
||||
.<Message<ExecuteObject>>create(sink -> {
|
||||
executeConsumer.handler(sink::next);
|
||||
@ -170,9 +153,7 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
.single()
|
||||
.timeout(Duration.ofSeconds(60 + 30))
|
||||
.doOnSuccess(s -> logger.trace("Executed successfully. Request was {}", request))
|
||||
.onErrorResume(ex -> Mono.fromRunnable(() -> {
|
||||
msg.fail(500, ex.getLocalizedMessage());
|
||||
}))
|
||||
.onErrorResume(ex -> Mono.fromRunnable(() -> msg.fail(500, ex.getLocalizedMessage())))
|
||||
.flatMap(response -> Mono.fromCallable(() -> {
|
||||
var replyOpts = new DeliveryOptions().setLocalOnly(local);
|
||||
var replyValue = new TdResultMessage(response.result(), response.cause());
|
||||
@ -197,10 +178,7 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
);
|
||||
|
||||
MessageConsumer<byte[]> readBinlogConsumer = vertx.eventBus().consumer(botAddress + ".read-binlog");
|
||||
if (this.readBinlogConsumer.tryEmitValue(readBinlogConsumer).isFailure()) {
|
||||
registrationSink.error(new IllegalStateException("Failed to set readBinlogConsumer"));
|
||||
return;
|
||||
}
|
||||
this.readBinlogConsumer.set(readBinlogConsumer);
|
||||
BinlogUtils
|
||||
.readBinlogConsumer(vertx, readBinlogConsumer, botId, local)
|
||||
.subscribeOn(Schedulers.parallel())
|
||||
@ -208,13 +186,10 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
|
||||
MessageConsumer<byte[]> readyToReceiveConsumer = vertx.eventBus().consumer(botAddress
|
||||
+ ".ready-to-receive");
|
||||
if (this.readyToReceiveConsumer.tryEmitValue(readyToReceiveConsumer).isFailure()) {
|
||||
registrationSink.error(new IllegalStateException("Failed to set readyToReceiveConsumer"));
|
||||
return;
|
||||
}
|
||||
this.readyToReceiveConsumer.set(readyToReceiveConsumer);
|
||||
|
||||
// Pipe the data
|
||||
var pipeSubscription = Flux
|
||||
Flux
|
||||
.<Message<byte[]>>create(sink -> {
|
||||
readyToReceiveConsumer.handler(sink::next);
|
||||
readyToReceiveConsumer.endHandler(h -> sink.complete());
|
||||
@ -222,10 +197,7 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
.take(1, true)
|
||||
.single()
|
||||
.doOnNext(s -> logger.trace("Received ready-to-receive request from client"))
|
||||
.flatMap(msg -> this.pipeFlux
|
||||
.asMono()
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.map(pipeFlux -> Tuples.of(msg, pipeFlux)))
|
||||
.map(msg -> Tuples.of(msg, Objects.requireNonNull(pipeFlux.get(), "PipeFlux is empty")))
|
||||
.doOnError(ex -> logger.error("Error when processing a ready-to-receive request", ex))
|
||||
.doOnNext(s -> logger.trace("Replying to ready-to-receive request"))
|
||||
.flatMapMany(tuple -> {
|
||||
@ -238,9 +210,7 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
logger.trace("Start piping data");
|
||||
|
||||
// Start piping the data
|
||||
return tuple.getT2().doOnSubscribe(s -> {
|
||||
logger.trace("Subscribed to updates pipe");
|
||||
});
|
||||
return tuple.getT2().doOnSubscribe(s -> logger.trace("Subscribed to updates pipe"));
|
||||
})
|
||||
.then()
|
||||
.doOnSuccess(s -> logger.trace("Finished handling ready-to-receive requests (updates pipe ended)"))
|
||||
@ -249,10 +219,7 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
.subscribe(v -> {});
|
||||
|
||||
MessageConsumer<byte[]> pingConsumer = vertx.eventBus().consumer(botAddress + ".ping");
|
||||
if (this.pingConsumer.tryEmitValue(pingConsumer).isFailure()) {
|
||||
registrationSink.error(new IllegalStateException("Failed to set pingConsumer"));
|
||||
return;
|
||||
}
|
||||
this.pingConsumer.set(pingConsumer);
|
||||
Flux
|
||||
.<Message<byte[]>>create(sink -> {
|
||||
pingConsumer.handler(sink::next);
|
||||
@ -288,61 +255,52 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
* Override some requests
|
||||
*/
|
||||
private Function overrideRequest(Function request, int botId) {
|
||||
switch (request.getConstructor()) {
|
||||
case SetTdlibParameters.CONSTRUCTOR:
|
||||
// Fix session directory locations
|
||||
var setTdlibParamsObj = (SetTdlibParameters) request;
|
||||
setTdlibParamsObj.parameters.databaseDirectory = TDLibRemoteClient.getSessionDirectory(botId).toString();
|
||||
setTdlibParamsObj.parameters.filesDirectory = TDLibRemoteClient.getMediaDirectory(botId).toString();
|
||||
return request;
|
||||
default:
|
||||
return request;
|
||||
if (request.getConstructor() == SetTdlibParameters.CONSTRUCTOR) {
|
||||
// Fix session directory locations
|
||||
var setTdlibParamsObj = (SetTdlibParameters) request;
|
||||
setTdlibParamsObj.parameters.databaseDirectory = TDLibRemoteClient.getSessionDirectory(botId).toString();
|
||||
setTdlibParamsObj.parameters.filesDirectory = TDLibRemoteClient.getMediaDirectory(botId).toString();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable rxStop() {
|
||||
return MonoUtils.toCompletable(botAlias
|
||||
.asMono()
|
||||
.timeout(Duration.ofSeconds(1), Mono.just("???"))
|
||||
.flatMap(botAlias -> Mono
|
||||
.fromRunnable(() -> logger.info("Undeploy of bot \"" + botAlias + "\": stopping"))
|
||||
.then(executeConsumer
|
||||
.asMono()
|
||||
.timeout(Duration.ofSeconds(5), Mono.empty())
|
||||
.flatMap(ec -> ec.rxUnregister().as(MonoUtils::toMono))
|
||||
.doOnSuccess(s -> logger.trace("Unregistered execute consumer"))
|
||||
)
|
||||
.then(readBinlogConsumer
|
||||
.asMono()
|
||||
.timeout(Duration.ofSeconds(10), Mono.empty())
|
||||
.flatMap(ec -> Mono.fromCallable(() -> {
|
||||
Mono
|
||||
// ReadBinLog will live for another 30 minutes.
|
||||
// Since every consumer of ReadBinLog is identical, this should not pose a problem.
|
||||
.delay(Duration.ofMinutes(30))
|
||||
.then(ec.rxUnregister().as(MonoUtils::toMono))
|
||||
.subscribe();
|
||||
return null;
|
||||
}).subscribeOn(Schedulers.boundedElastic()))
|
||||
)
|
||||
.then(readyToReceiveConsumer
|
||||
.asMono()
|
||||
.timeout(Duration.ofSeconds(5), Mono.empty())
|
||||
.flatMap(ec -> ec.rxUnregister().as(MonoUtils::toMono)))
|
||||
.then(pingConsumer
|
||||
.asMono()
|
||||
.timeout(Duration.ofSeconds(5), Mono.empty())
|
||||
.flatMap(ec -> ec.rxUnregister().as(MonoUtils::toMono)))
|
||||
.doOnError(ex -> logger.error("Undeploy of bot \"" + botAlias + "\": stop failed", ex))
|
||||
.doOnTerminate(() -> logger.info("Undeploy of bot \"" + botAlias + "\": stopped"))
|
||||
return MonoUtils.toCompletable(Mono
|
||||
.fromRunnable(() -> logger.info("Undeploy of bot \"" + botAlias.get() + "\": stopping"))
|
||||
.then(Mono
|
||||
.fromCallable(executeConsumer::get)
|
||||
.flatMap(executeConsumer -> executeConsumer.rxUnregister().as(MonoUtils::toMono))
|
||||
.doOnSuccess(s -> logger.trace("Unregistered execute consumer"))
|
||||
)
|
||||
.then(MonoUtils.fromBlockingEmpty(() -> {
|
||||
var readBinlogConsumer = this.readBinlogConsumer.get();
|
||||
if (readBinlogConsumer != null) {
|
||||
Mono
|
||||
// ReadBinLog will live for another 10 minutes.
|
||||
// Since every consumer of ReadBinLog is identical, this should not pose a problem.
|
||||
.delay(Duration.ofMinutes(10))
|
||||
.then(readBinlogConsumer.rxUnregister().as(MonoUtils::toMono))
|
||||
.subscribe();
|
||||
}
|
||||
}))
|
||||
.then(Mono
|
||||
.fromCallable(readyToReceiveConsumer::get)
|
||||
.flatMap(ec -> ec.rxUnregister().as(MonoUtils::toMono))
|
||||
)
|
||||
.then(Mono
|
||||
.fromCallable(pingConsumer::get)
|
||||
.flatMap(ec -> ec.rxUnregister().as(MonoUtils::toMono))
|
||||
)
|
||||
.doOnError(ex -> logger.error("Undeploy of bot \"" + botAlias.get() + "\": stop failed", ex))
|
||||
.doOnTerminate(() -> logger.info("Undeploy of bot \"" + botAlias.get() + "\": stopped"))
|
||||
);
|
||||
}
|
||||
|
||||
private Mono<Void> pipe(AsyncTdDirectImpl td, String botAddress, String botAlias, int botId, boolean local) {
|
||||
private Mono<Void> pipe(AsyncTdDirectImpl td, String botAddress, boolean local) {
|
||||
logger.trace("Preparing to pipe requests");
|
||||
Flux<TdResultList> updatesFlux = td.receive(tdOptions)
|
||||
Flux<TdResultList> updatesFlux = td
|
||||
.receive(tdOptions)
|
||||
.takeUntil(item -> {
|
||||
if (item instanceof Update) {
|
||||
var tdUpdate = (Update) item;
|
||||
@ -437,7 +395,9 @@ public class AsyncTdMiddleEventBusServer extends AbstractVerticle {
|
||||
.then(rxStop().as(MonoUtils::toMono));
|
||||
});
|
||||
|
||||
return MonoUtils.emitValue(this.pipeFlux, pipeFlux)
|
||||
.doOnSuccess(s -> logger.trace("Prepared piping requests successfully"));
|
||||
return MonoUtils.fromBlockingEmpty(() -> {
|
||||
this.pipeFlux.set(pipeFlux);
|
||||
logger.trace("Prepared piping requests successfully");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -161,65 +161,6 @@ public class MonoUtils {
|
||||
return Completable.fromPublisher(s);
|
||||
}
|
||||
|
||||
public static Mono<Void> fromEmitResult(EmitResult emitResult) {
|
||||
return Mono.fromCallable(() -> {
|
||||
emitResult.orThrow();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static Future<Void> fromEmitResultFuture(EmitResult emitResult) {
|
||||
if (emitResult.isSuccess()) {
|
||||
return Future.succeededFuture();
|
||||
} else {
|
||||
return Future.failedFuture(new EmissionException(emitResult));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Mono<Void> emitValue(One<T> sink, T value) {
|
||||
return Mono.defer(() -> fromEmitResult(sink.tryEmitValue(value)));
|
||||
}
|
||||
|
||||
public static <T> Mono<Void> emitNext(Many<T> sink, T value) {
|
||||
return Mono.defer(() -> fromEmitResult(sink.tryEmitNext(value)));
|
||||
}
|
||||
|
||||
public static <T> Mono<Void> emitComplete(Many<T> sink) {
|
||||
return Mono.defer(() -> fromEmitResult(sink.tryEmitComplete()));
|
||||
}
|
||||
|
||||
public static <T> Mono<Void> emitEmpty(Empty<T> sink) {
|
||||
return Mono.defer(() -> fromEmitResult(sink.tryEmitEmpty()));
|
||||
}
|
||||
|
||||
public static <T> Mono<Void> emitEmpty(One<T> sink) {
|
||||
return Mono.defer(() -> fromEmitResult(sink.tryEmitEmpty()));
|
||||
}
|
||||
|
||||
public static <T> Mono<Void> emitError(Empty<T> sink, Throwable value) {
|
||||
return Mono.defer(() -> fromEmitResult(sink.tryEmitError(value)));
|
||||
}
|
||||
|
||||
public static <T> Future<Void> emitValueFuture(One<T> sink, T value) {
|
||||
return fromEmitResultFuture(sink.tryEmitValue(value));
|
||||
}
|
||||
|
||||
public static <T> Future<Void> emitNextFuture(Many<T> sink, T value) {
|
||||
return fromEmitResultFuture(sink.tryEmitNext(value));
|
||||
}
|
||||
|
||||
public static <T> Future<Void> emitCompleteFuture(Many<T> sink) {
|
||||
return fromEmitResultFuture(sink.tryEmitComplete());
|
||||
}
|
||||
|
||||
public static <T> Future<Void> emitErrorFuture(Empty<T> sink, Throwable value) {
|
||||
return fromEmitResultFuture(sink.tryEmitError(value));
|
||||
}
|
||||
|
||||
public static <T> Future<Void> emitEmptyFuture(Empty<T> sink) {
|
||||
return fromEmitResultFuture(sink.tryEmitEmpty());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static <T> Mono<T> castVoid(Mono<Void> mono) {
|
||||
return (Mono) mono;
|
||||
|
Loading…
x
Reference in New Issue
Block a user