RSocket Net client request stream routing metadata to spring boot @MessageMapping routes

822 Views Asked by At

Similar to rsocket routing metadata using RSocket-Java for Spring Rsocket Server but for an RSocket Net Client, we use a spring boot @MessageMapping for websocket endpoint routes on port 7000 which return webfluxes depending on the route. For example:

@MessageMapping(value = "helloWorld")
public Flux<String> getFluxSocket() {
    log.traceEntry();
    log.info("In hello world");
    
    return Flux.just("{\"Hello\":\"World\"}");
}

When spring boot server is running locally, to get this flux you can use rsc client

java -jar rsc.jar --debug --request --route helloWorld ws://localhost:7000

Or for a stream

java -jar rsc.jar --debug --stream --route myStream ws://localhost:7000

To do this programmatically in C# Net it says here that request routing is not yet supported in RSocket Net but can use metadata payload. Has anyone got the Net equivalent of this?

CompositeByteBuf metadata = ByteBufAllocator.DEFAULT.compositeBuffer();
RoutingMetadata routingMetadata = TaggingMetadataCodec.createRoutingMetadata(ByteBufAllocator.DEFAULT, List.of("/route"));
CompositeMetadataCodec.encodeAndAddMetadata(metadata,
        ByteBufAllocator.DEFAULT,
        WellKnownMimeType.MESSAGE_RSOCKET_ROUTING,
        routingMetadata.getContent());

Thanks

2

There are 2 best solutions below

1
On BEST ANSWER

To get the RSocket net routes working for string client, use

var client = new RSocketClient(new WebSocketTransport("ws://127.0.0.1:7000/"));

Console.WriteLine("Connect Async");
await client.ConnectAsync(new RSocketOptions()
{
    MetadataMimeType = "message/x.rsocket.routing.v0",      
    DataMimeType = "application/json"
});

String json = "{\"Hello\":\"World\"}

byte[] intBytes = BitConverter.GetBytes(6);
string stringBytes = Encoding.Default.GetString(intBytes, 0, 1);
string metaData = stringBytes + route;

var stringclient = new RSocketClient.ForStrings(client);
await stringclient.RequestStream(json, metaData)
.ForEachAsync((result) =>
{
    Console.WriteLine($"Result ===> {result}");
});

To get the RSocket net routes working for binary client, use

var client = new RSocketClient(new WebSocketTransport("ws://localhost:8080/"));
await client.ConnectAsync(new RSocketOptions()
{
    MetadataMimeType = "message/x.rsocket.routing.v0",
    DataMimeType = "application/octet-stream"
});

Console.WriteLine("Requesting Raw Protobuf Stream...");

var route = new ReadOnlySequence<byte>(new byte[]
{
    (byte) Encoding.UTF8.GetByteCount("request.stream")
}.Concat(Encoding.UTF8.GetBytes("request.stream")).ToArray());

//Make a Raw binary call
var stream = client.RequestStream(
    resultmapper: result => 
(Data: Encoding.UTF8.GetString(result.data.ToArray()), 
Metadata: Encoding.UTF8.GetString(result.metadata.ToArray())),
data: new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes("test")), 
metadata: route);

await stream.ForEachAsync(persons => 
Console.WriteLine($"RawDemo.OnNext===>[{persons.Metadata}]{persons.Data}"));
3
On

You can implement routing metadata until the .NET library officially supports routing / compsite metadata. If you don't need to send any metadata other than routing metadata, you don't need to create composite metadata. Sending only routing metadata is pretty simple.

As you can see from the spec, just add the length of the route name to the first byte. https://github.com/rsocket/rsocket/blob/master/Extensions/Routing.md

I have no knowledge of .NET, so I'll show you how to implement it in Java and JavaScript instead. FYI.

https://github.com/making/demo-rsocket/blob/master/vanilla-rsocket-client/src/main/java/com/example/vanillarsocketclient/VanillaRsocketClientApplication.java

static ByteBuffer routingMetadata(String tag) {
    final byte[] bytes = tag.getBytes(StandardCharsets.UTF_8);
    final ByteBuffer buffer = ByteBuffer.allocate(1 + bytes.length);
    buffer.put((byte) bytes.length);
    buffer.put(bytes);
    buffer.flip();
    return buffer;
}

https://github.com/making/demo-rsocket-jsug/blob/master/frontend/vanilla/src/index.js

const routingMetadata = (route) => {
    return String.fromCharCode(route.length) + route;
};