Initial rsocket-broker sample
This commit is contained in:
@@ -18,11 +18,16 @@ package org.springframework.cloud.function.rsocket;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import io.rsocket.RSocket;
|
||||
import io.rsocket.SocketAcceptor;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.FunctionProperties;
|
||||
@@ -36,28 +41,39 @@ import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.messaging.rsocket.RSocketConnectorConfigurer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Main configuration class for components required to support RSocket integration with spring-cloud-function.
|
||||
* Main configuration class for components required to support RSocket integration with
|
||||
* spring-cloud-function.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 3.1
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties({FunctionProperties.class, RSocketFunctionProperties.class})
|
||||
@EnableConfigurationProperties({ FunctionProperties.class, RSocketFunctionProperties.class })
|
||||
@ConditionalOnProperty(name = FunctionProperties.PREFIX + ".rsocket.enabled", matchIfMissing = true)
|
||||
@AutoConfigureBefore(name = "io.rsocket.routing.client.spring.RoutingClientAutoConfiguration")
|
||||
public class RSocketAutoConfiguration {
|
||||
|
||||
private static Log logger = LogFactory.getLog(RSocketAutoConfiguration.class);
|
||||
|
||||
|
||||
@Bean
|
||||
public FunctionToRSocketBinder functionToDestinationBinder(FunctionCatalog functionCatalog,
|
||||
FunctionProperties functionProperties, RSocketFunctionProperties rSocketFunctionProperties) {
|
||||
return new FunctionToRSocketBinder(functionCatalog, functionProperties, rSocketFunctionProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "io.rsocket.routing.client.spring.RoutingClientAutoConfiguration")
|
||||
//TODO: move to broker specific auto config
|
||||
public RSocketConnectorConfigurer functionRSocketConnectorConfigurer(
|
||||
FunctionToRSocketBinder binder) {
|
||||
return connector -> connector.acceptor(SocketAcceptor.with(binder.getRSocket()));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -81,6 +97,7 @@ public class RSocketAutoConfiguration {
|
||||
this.functionProperties = functionProperties;
|
||||
this.rSocketFunctionProperties = rSocketFunctionProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String definition = this.functionProperties.getDefinition();
|
||||
@@ -92,16 +109,28 @@ public class RSocketAutoConfiguration {
|
||||
}
|
||||
Assert.isTrue(StringUtils.hasText(definition), "Failed to determine target function for RSocket.");
|
||||
this.registerRsocketForwardingFunctionIfNecessary(definition);
|
||||
//TODO externalize content-type
|
||||
// TODO externalize content-type
|
||||
FunctionInvocationWrapper function = functionCatalog.lookup(definition, "application/json");
|
||||
if (function.isSupplier()) {
|
||||
throw new UnsupportedOperationException("Supplier is not currently supported for RSocket interaction");
|
||||
}
|
||||
|
||||
InetSocketAddress bindAddress = InetSocketAddress
|
||||
.createUnresolved(this.rSocketFunctionProperties.getBindAddress(), this.rSocketFunctionProperties.getBindPort());
|
||||
if (StringUtils.hasText(rSocketFunctionProperties.getBindAddress())
|
||||
&& rSocketFunctionProperties.getBindPort() != null) {
|
||||
InetSocketAddress bindAddress = InetSocketAddress.createUnresolved(
|
||||
this.rSocketFunctionProperties.getBindAddress(), this.rSocketFunctionProperties.getBindPort());
|
||||
this.invocableFunction = new RSocketListenerFunction(function, bindAddress);
|
||||
}
|
||||
else {
|
||||
this.invocableFunction = new RSocketListenerFunction(function, null);
|
||||
}
|
||||
}
|
||||
|
||||
this.invocableFunction = new RSocketListenerFunction(function, bindAddress);
|
||||
RSocket getRSocket() {
|
||||
if (this.invocableFunction == null) {
|
||||
return null;
|
||||
}
|
||||
return this.invocableFunction.getRsocket();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@@ -115,16 +144,18 @@ public class RSocketAutoConfiguration {
|
||||
}
|
||||
String[] functionToRSocketDefinition = StringUtils.delimitedListToStringArray(name, ">");
|
||||
Assert.isTrue(functionToRSocketDefinition.length == 2, "Must only contain one output redirect");
|
||||
FunctionInvocationWrapper function = functionCatalog.lookup(functionToRSocketDefinition[0], "application/json");
|
||||
FunctionInvocationWrapper function = functionCatalog.lookup(functionToRSocketDefinition[0],
|
||||
"application/json");
|
||||
|
||||
String[] hostPort = StringUtils.delimitedListToStringArray(functionToRSocketDefinition[1], ":");
|
||||
InetSocketAddress outputAddress = InetSocketAddress
|
||||
.createUnresolved(hostPort[0], Integer.valueOf(hostPort[1]));
|
||||
InetSocketAddress outputAddress = InetSocketAddress.createUnresolved(hostPort[0],
|
||||
Integer.valueOf(hostPort[1]));
|
||||
|
||||
RSocketForwardingFunction rsocketFunction = new RSocketForwardingFunction(function, outputAddress);
|
||||
FunctionRegistration functionRegistration = new FunctionRegistration(rsocketFunction, name);
|
||||
|
||||
functionRegistration.type(FunctionTypeUtils.discoverFunctionTypeFromClass(RSocketListenerFunction.class));
|
||||
functionRegistration
|
||||
.type(FunctionTypeUtils.discoverFunctionTypeFromClass(RSocketListenerFunction.class));
|
||||
((FunctionRegistry) this.functionCatalog).register(functionRegistration);
|
||||
}
|
||||
}
|
||||
@@ -141,15 +172,19 @@ public class RSocketAutoConfiguration {
|
||||
this.invocableFunction.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.isRunning() && this.invocableFunction != null) {
|
||||
this.invocableFunction.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.started;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,9 +29,19 @@ import org.springframework.cloud.function.context.FunctionProperties;
|
||||
@ConfigurationProperties(prefix = FunctionProperties.PREFIX + ".rsocket")
|
||||
public class RSocketFunctionProperties {
|
||||
|
||||
private String bindAddress = "localhost";
|
||||
private boolean enabled;
|
||||
|
||||
private int bindPort = 55555;
|
||||
private String bindAddress;
|
||||
|
||||
private Integer bindPort;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getBindAddress() {
|
||||
return bindAddress;
|
||||
@@ -41,11 +51,11 @@ public class RSocketFunctionProperties {
|
||||
this.bindAddress = bindAddress;
|
||||
}
|
||||
|
||||
public int getBindPort() {
|
||||
public Integer getBindPort() {
|
||||
return bindPort;
|
||||
}
|
||||
|
||||
public void setBindPort(int bindPort) {
|
||||
public void setBindPort(Integer bindPort) {
|
||||
this.bindPort = bindPort;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ public class RSocketListenerFunction implements Function<Message<byte[]>, Publis
|
||||
private final FunctionInvocationWrapper targetFunction;
|
||||
|
||||
private Disposable rsocketConnection;
|
||||
private RSocket rsocket;
|
||||
|
||||
RSocketListenerFunction(FunctionInvocationWrapper targetFunction, InetSocketAddress listenAddress) {
|
||||
this.listenAddress = listenAddress;
|
||||
@@ -80,7 +81,9 @@ public class RSocketListenerFunction implements Function<Message<byte[]>, Publis
|
||||
void start() {
|
||||
Type functionType = this.targetFunction.getFunctionType();
|
||||
|
||||
RSocket rsocket = buildRSocket(this.targetFunction.getFunctionDefinition(), functionType, this);
|
||||
if (rsocket == null) {
|
||||
rsocket = buildRSocket(this.targetFunction, functionType, this);
|
||||
}
|
||||
if (this.listenAddress != null) {
|
||||
this.rsocketConnection = RSocketConnectionUtils.createServerSocket(rsocket, this.listenAddress);
|
||||
this.printSplashScreen(this.targetFunction.getFunctionDefinition(), functionType);
|
||||
@@ -93,7 +96,15 @@ public class RSocketListenerFunction implements Function<Message<byte[]>, Publis
|
||||
}
|
||||
}
|
||||
|
||||
private RSocket buildRSocket(String definition, Type functionType, Function<Message<byte[]>, Publisher<Message<byte[]>>> function) {
|
||||
public RSocket getRsocket() {
|
||||
if (this.rsocket == null) {
|
||||
start();
|
||||
}
|
||||
return this.rsocket;
|
||||
}
|
||||
|
||||
private RSocket buildRSocket(FunctionInvocationWrapper targetFunction, Type functionType, Function<Message<byte[]>, Publisher<Message<byte[]>>> function) {
|
||||
String definition = targetFunction.getFunctionDefinition();
|
||||
RSocket clientRSocket = new RSocket() { // imperative function or Function<?, Mono> = requestResponse
|
||||
@Override
|
||||
public Mono<Payload> requestResponse(Payload payload) {
|
||||
|
||||
Reference in New Issue
Block a user