io.scalecube.services.transport.rsocket.RSocketServiceTransport Maven / Gradle / Ivy
package io.scalecube.services.transport.rsocket;
import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.scalecube.services.transport.api.ClientTransport;
import io.scalecube.services.transport.api.HeadersCodec;
import io.scalecube.services.transport.api.ServerTransport;
import io.scalecube.services.transport.api.ServiceMessageCodec;
import io.scalecube.services.transport.api.ServiceTransport;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.function.Function;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.FutureMono;
import reactor.netty.resources.LoopResources;
import reactor.netty.tcp.TcpClient;
import reactor.netty.tcp.TcpServer;
/** RSocket service transport. */
public class RSocketServiceTransport implements ServiceTransport {
private static final HeadersCodec HEADERS_CODEC = HeadersCodec.getInstance("application/json");
private static final int NUM_OF_WORKERS = Runtime.getRuntime().availableProcessors();
private int numOfWorkers = NUM_OF_WORKERS;
private HeadersCodec headersCodec = HEADERS_CODEC;
private Function tcpServerProvider = defaultTcpServerProvider();
private Function tcpClientProvider = defaultTcpClientProvider();
// resources
private EventLoopGroup eventLoopGroup;
private LoopResources clientLoopResources;
private LoopResources serverLoopResources;
/** Default constructor. */
public RSocketServiceTransport() {}
/**
* Copy constructor.
*
* @param other other instance
*/
private RSocketServiceTransport(RSocketServiceTransport other) {
this.numOfWorkers = other.numOfWorkers;
this.headersCodec = other.headersCodec;
this.eventLoopGroup = other.eventLoopGroup;
this.clientLoopResources = other.clientLoopResources;
this.serverLoopResources = other.serverLoopResources;
}
/**
* Sets a worker threads number.
*
* @param numOfWorkers number of worker threads
* @return new {@code RSocketServiceTransport} instance
*/
public RSocketServiceTransport numOfWorkers(int numOfWorkers) {
RSocketServiceTransport rst = new RSocketServiceTransport(this);
rst.numOfWorkers = numOfWorkers;
return rst;
}
/**
* Sets a {@code HeadersCodec}.
*
* @param headersCodec headers codec
* @return new {@code RSocketServiceTransport} instance
*/
public RSocketServiceTransport headersCodec(HeadersCodec headersCodec) {
RSocketServiceTransport rst = new RSocketServiceTransport(this);
rst.headersCodec = headersCodec;
return rst;
}
/**
* Sets a provider function for custom {@code TcpServer}.
*
* @param factory {@code TcpServer} provider function
* @return new {@code RSocketServiceTransport} instance
*/
public RSocketServiceTransport tcpServer(Function factory) {
RSocketServiceTransport rst = new RSocketServiceTransport(this);
rst.tcpServerProvider = factory;
return rst;
}
/**
* Sets a provider function for custom {@code TcpClient}.
*
* @param factory {@code TcpClient} provider function
* @return new {@code RSocketServiceTransport} instance
*/
public RSocketServiceTransport tcpClient(Function factory) {
RSocketServiceTransport rst = new RSocketServiceTransport(this);
rst.tcpClientProvider = factory;
return rst;
}
/**
* Fabric method for client transport.
*
* @return client transport
*/
@Override
public ClientTransport clientTransport() {
return new RSocketClientTransport(
new ServiceMessageCodec(headersCodec), tcpClientProvider.apply(clientLoopResources));
}
/**
* Fabric method for server transport.
*
* @return server transport
*/
@Override
public ServerTransport serverTransport() {
return new RSocketServerTransport(
new ServiceMessageCodec(headersCodec), tcpServerProvider.apply(serverLoopResources));
}
@Override
public Mono start() {
return Mono.fromRunnable(this::start0).thenReturn(this);
}
@Override
public Mono stop() {
return Flux.concatDelayError(
Mono.defer(() -> serverLoopResources.disposeLater()),
Mono.defer(this::shutdownEventLoopGroup))
.then();
}
private void start0() {
eventLoopGroup = newEventLoopGroup();
clientLoopResources = DelegatedLoopResources.newClientLoopResources(eventLoopGroup);
serverLoopResources = DelegatedLoopResources.newServerLoopResources(eventLoopGroup);
}
private EventLoopGroup newEventLoopGroup() {
return Epoll.isAvailable()
? new ExtendedEpollEventLoopGroup(numOfWorkers, this::chooseEventLoop)
: new ExtendedNioEventLoopGroup(numOfWorkers, this::chooseEventLoop);
}
private EventLoop chooseEventLoop(Channel channel, Iterator executors) {
while (executors.hasNext()) {
EventExecutor eventLoop = executors.next();
if (eventLoop.inEventLoop()) {
return (EventLoop) eventLoop;
}
}
return null;
}
private Mono shutdownEventLoopGroup() {
//noinspection unchecked
return Mono.defer(() -> FutureMono.from((Future) eventLoopGroup.shutdownGracefully()));
}
private Function defaultTcpServerProvider() {
return (LoopResources serverLoopResources) ->
TcpServer.create()
.runOn(serverLoopResources)
.addressSupplier(() -> new InetSocketAddress(0));
}
private Function defaultTcpClientProvider() {
return (LoopResources clientLoopResources) ->
TcpClient.newConnection().runOn(clientLoopResources);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy