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