2022-10-06 00:36:00 +02:00
|
|
|
package it.tdlight.reactiveapi.rsocket;
|
|
|
|
|
2022-10-11 20:08:40 +02:00
|
|
|
import static reactor.util.concurrent.Queues.XS_BUFFER_SIZE;
|
|
|
|
|
2022-10-06 00:36:00 +02:00
|
|
|
import com.google.common.net.HostAndPort;
|
2022-11-09 18:56:28 +01:00
|
|
|
import io.rsocket.Closeable;
|
2022-10-06 00:36:00 +02:00
|
|
|
import io.rsocket.ConnectionSetupPayload;
|
|
|
|
import io.rsocket.Payload;
|
|
|
|
import io.rsocket.RSocket;
|
|
|
|
import io.rsocket.SocketAcceptor;
|
|
|
|
import io.rsocket.core.RSocketServer;
|
|
|
|
import io.rsocket.frame.decoder.PayloadDecoder;
|
2022-11-09 18:56:28 +01:00
|
|
|
import io.rsocket.transport.ServerTransport;
|
2022-10-06 00:36:00 +02:00
|
|
|
import io.rsocket.transport.netty.server.CloseableChannel;
|
|
|
|
import io.rsocket.transport.netty.server.TcpServerTransport;
|
|
|
|
import io.rsocket.util.DefaultPayload;
|
|
|
|
import it.tdlight.reactiveapi.ChannelCodec;
|
2022-10-07 16:03:51 +02:00
|
|
|
import it.tdlight.reactiveapi.Deserializer;
|
2022-10-06 00:36:00 +02:00
|
|
|
import it.tdlight.reactiveapi.EventConsumer;
|
|
|
|
import it.tdlight.reactiveapi.EventProducer;
|
2022-10-07 16:03:51 +02:00
|
|
|
import it.tdlight.reactiveapi.Serializer;
|
2022-10-06 00:36:00 +02:00
|
|
|
import it.tdlight.reactiveapi.Timestamped;
|
2022-11-09 18:56:28 +01:00
|
|
|
import it.tdlight.reactiveapi.TransportFactory;
|
2022-10-10 01:05:53 +02:00
|
|
|
import java.io.IOException;
|
2022-10-06 00:36:00 +02:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
2022-10-06 19:06:35 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
2022-10-06 00:36:00 +02:00
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
2022-10-06 19:06:35 +02:00
|
|
|
import org.reactivestreams.Publisher;
|
2022-10-06 00:36:00 +02:00
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
import reactor.core.publisher.Mono;
|
2022-10-06 19:06:35 +02:00
|
|
|
import reactor.core.scheduler.Schedulers;
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-06 19:06:35 +02:00
|
|
|
public class MyRSocketServer implements RSocketChannelManager, RSocket {
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-06 19:06:35 +02:00
|
|
|
private final Logger logger = LogManager.getLogger(this.getClass());
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-11 20:08:40 +02:00
|
|
|
private final int bufferSize;
|
2022-11-09 18:56:28 +01:00
|
|
|
private final Mono<Closeable> serverCloseable;
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-06 19:06:35 +02:00
|
|
|
protected final Map<String, ConsumerConnection<?>> consumerRegistry = new ConcurrentHashMap<>();
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-06 19:06:35 +02:00
|
|
|
protected final Map<String, ProducerConnection<?>> producerRegistry = new ConcurrentHashMap<>();
|
2022-10-06 00:36:00 +02:00
|
|
|
|
|
|
|
public MyRSocketServer(HostAndPort baseHost) {
|
2022-11-09 18:56:28 +01:00
|
|
|
this(TransportFactory.tcp(baseHost));
|
2022-10-11 20:08:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public MyRSocketServer(HostAndPort baseHost, int bufferSize) {
|
2022-11-09 18:56:28 +01:00
|
|
|
this(TransportFactory.tcp(baseHost), bufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MyRSocketServer(TransportFactory transportFactory) {
|
|
|
|
this(transportFactory, XS_BUFFER_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MyRSocketServer(TransportFactory transportFactory, int bufferSize) {
|
2022-10-11 20:08:40 +02:00
|
|
|
this.bufferSize = bufferSize;
|
2022-11-09 18:56:28 +01:00
|
|
|
Mono<Closeable> serverMono = RSocketServer
|
2022-10-10 01:05:53 +02:00
|
|
|
.create(new SocketAcceptor() {
|
|
|
|
@Override
|
|
|
|
public @NotNull Mono<RSocket> accept(@NotNull ConnectionSetupPayload setup, @NotNull RSocket sendingSocket) {
|
|
|
|
if (setup.getMetadataUtf8().equals("setup-info") && setup.getDataUtf8().equals("client")) {
|
|
|
|
return Mono.just(MyRSocketServer.this);
|
|
|
|
} else {
|
|
|
|
return Mono.error(new IOException("Invalid credentials"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2022-10-06 00:36:00 +02:00
|
|
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
2022-11-09 18:56:28 +01:00
|
|
|
.bind(transportFactory.getServerTransport(0))
|
|
|
|
.cast(Object.class)
|
2022-10-06 19:06:35 +02:00
|
|
|
.doOnNext(d -> logger.debug("Server up"))
|
2022-11-09 18:56:28 +01:00
|
|
|
.cacheInvalidateIf(t -> t instanceof Closeable closeableChannel && closeableChannel.isDisposed())
|
|
|
|
.filter(t -> t instanceof Closeable)
|
|
|
|
.cast(Closeable.class)
|
|
|
|
.defaultIfEmpty(new Closeable() {
|
|
|
|
@Override
|
|
|
|
public void dispose() {}
|
|
|
|
@Override
|
|
|
|
public @NotNull Mono<Void> onClose() {
|
|
|
|
return Mono.empty();
|
|
|
|
}
|
|
|
|
});
|
2022-10-06 19:06:35 +02:00
|
|
|
|
|
|
|
serverMono.subscribeOn(Schedulers.parallel()).subscribe(v -> {}, ex -> logger.warn("Failed to bind server"));
|
|
|
|
|
|
|
|
this.serverCloseable = serverMono;
|
2022-10-06 00:36:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-10-06 19:06:35 +02:00
|
|
|
public @NotNull Flux<Payload> requestChannel(@NotNull Publisher<Payload> payloads) {
|
|
|
|
return Flux.from(payloads).switchOnFirst((first, flux) -> {
|
|
|
|
if (first.isOnNext()) {
|
|
|
|
var firstValue = first.get();
|
|
|
|
assert firstValue != null;
|
|
|
|
var meta = firstValue.getMetadataUtf8();
|
|
|
|
if (!meta.equals("channel")) {
|
|
|
|
return Mono.error(new CancelledChannelException("Metadata is wrong"));
|
|
|
|
}
|
|
|
|
var channel = firstValue.getDataUtf8();
|
2022-10-11 20:08:40 +02:00
|
|
|
var conn = MyRSocketServer.this.consumerRegistry.computeIfAbsent(channel,
|
|
|
|
ch -> new ConsumerConnection<>(ch, bufferSize));
|
2022-10-06 19:06:35 +02:00
|
|
|
conn.registerRemote(flux.skip(1));
|
|
|
|
return conn.connectRemote().then(Mono.fromSupplier(() -> DefaultPayload.create("ok", "result")));
|
|
|
|
} else {
|
|
|
|
return flux.take(1, true);
|
2022-10-06 00:36:00 +02:00
|
|
|
}
|
2022-10-06 19:06:35 +02:00
|
|
|
});
|
|
|
|
}
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-06 19:06:35 +02:00
|
|
|
@Override
|
|
|
|
public @NotNull Flux<Payload> requestStream(@NotNull Payload payload) {
|
|
|
|
var channel = payload.getDataUtf8();
|
|
|
|
return Flux.defer(() -> {
|
2022-10-11 20:08:40 +02:00
|
|
|
var conn = MyRSocketServer.this.producerRegistry.computeIfAbsent(channel,
|
|
|
|
ch -> new ProducerConnection<>(ch, bufferSize));
|
2022-10-06 19:06:35 +02:00
|
|
|
conn.registerRemote();
|
|
|
|
return conn.connectRemote();
|
|
|
|
});
|
|
|
|
}
|
2022-10-06 00:36:00 +02:00
|
|
|
|
2022-10-06 19:06:35 +02:00
|
|
|
@Override
|
|
|
|
public final <K> EventConsumer<K> registerConsumer(ChannelCodec channelCodec, String channelName) {
|
|
|
|
logger.debug("Registering consumer for channel \"{}\"", channelName);
|
|
|
|
Deserializer<K> deserializer;
|
|
|
|
try {
|
|
|
|
deserializer = channelCodec.getNewDeserializer();
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
logger.error("Failed to create codec for channel \"{}\"", channelName, ex);
|
|
|
|
throw new IllegalStateException("Failed to create codec for channel " + channelName);
|
|
|
|
}
|
|
|
|
return new EventConsumer<K>() {
|
2022-10-06 00:36:00 +02:00
|
|
|
@Override
|
|
|
|
public Flux<Timestamped<K>> consumeMessages() {
|
2022-10-07 00:48:10 +02:00
|
|
|
return serverCloseable.flatMapMany(x -> {
|
2022-10-06 19:06:35 +02:00
|
|
|
//noinspection unchecked
|
2022-10-11 20:08:40 +02:00
|
|
|
var conn = (ConsumerConnection<K>) consumerRegistry.computeIfAbsent(channelName,
|
|
|
|
ch -> new ConsumerConnection<>(ch, bufferSize));
|
|
|
|
Throwable ex = conn.registerLocal(deserializer);
|
|
|
|
if (ex != null) {
|
|
|
|
return Flux.error(ex);
|
|
|
|
}
|
2022-10-06 19:06:35 +02:00
|
|
|
return conn.connectLocal();
|
2022-10-06 00:36:00 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public <K> EventProducer<K> registerProducer(ChannelCodec channelCodec, String channelName) {
|
2022-10-06 19:06:35 +02:00
|
|
|
logger.debug("Registering producer for channel \"{}\"", channelName);
|
2022-10-06 00:36:00 +02:00
|
|
|
Serializer<K> serializer;
|
|
|
|
try {
|
|
|
|
serializer = channelCodec.getNewSerializer();
|
|
|
|
} catch (Throwable ex) {
|
2022-10-06 19:06:35 +02:00
|
|
|
logger.error("Failed to create codec for channel \"{}\"", channelName, ex);
|
|
|
|
throw new IllegalStateException("Failed to create codec for channel " + channelName);
|
2022-10-06 00:36:00 +02:00
|
|
|
}
|
2022-10-11 20:08:40 +02:00
|
|
|
return new EventProducer<>() {
|
2022-10-06 00:36:00 +02:00
|
|
|
@Override
|
|
|
|
public Mono<Void> sendMessages(Flux<K> eventsFlux) {
|
2022-10-07 00:48:10 +02:00
|
|
|
return serverCloseable.flatMap(x -> {
|
2022-10-06 19:06:35 +02:00
|
|
|
//noinspection unchecked
|
2022-10-11 20:08:40 +02:00
|
|
|
var conn = (ProducerConnection<K>) producerRegistry.computeIfAbsent(channelName,
|
|
|
|
ch -> new ProducerConnection<>(ch, bufferSize));
|
2022-10-06 19:06:35 +02:00
|
|
|
conn.registerLocal(eventsFlux.transform(flux -> RSocketUtils.serialize(flux, serializer)));
|
|
|
|
return conn.connectLocal();
|
2022-10-06 00:36:00 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void close() {
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public @NotNull Mono<Void> onClose() {
|
2022-11-09 18:56:28 +01:00
|
|
|
return Mono.when(serverCloseable.flatMap(Closeable::onClose));
|
2022-10-06 00:36:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void dispose() {
|
2022-10-06 19:06:35 +02:00
|
|
|
serverCloseable
|
2022-11-09 18:56:28 +01:00
|
|
|
.doOnNext(Closeable::dispose)
|
2022-10-06 19:06:35 +02:00
|
|
|
.subscribeOn(Schedulers.parallel())
|
|
|
|
.subscribe(v -> {}, ex -> logger.error("Failed to dispose the server", ex));
|
2022-10-06 00:36:00 +02:00
|
|
|
}
|
|
|
|
}
|