Hi folks, im using the kotlin-rsocket impl client ...
# rsocket
g
Hi folks, im using the kotlin-rsocket impl client to connect to a springboot-server (which is using the java-rsocket impl). Since it is a protocol, i guess it should fine, even if im using two different impls. Im getting an error about no destination handler:
io.rsocket.kotlin.RSocketError$ApplicationError: No handler for destination
. So im investigation a bit the spring code and i figured the routing-metada are not decoded properly, also i turned up the debugger in spring and it confirmed it for me after this:
DefaultMetadataExtractor   : Values extracted from metadata: {} with registrations for [].
So anyone has any ideas? Thanks in advance 🙂
o
Could you check, that both kotlin and java impl are configured to use CompositeMetadata or RoutingMetadata? AFAIK spring by default uses composite, but rsocket kotlin uses octet stream metadata type by default (so just binary)
g
Client code:
Copy code
internal inline fun <reified T, reified R> RSocket.hubRequestChannel(
    route: String,
    incomingFlow: Flow<T>
): Flow<HubPayload<R>> {
    val routePayload = routePayload(route)
    val payloads = incomingFlow.map { protoBufFormat.encodeToPayload(route, it) }
    return requestChannel(routePayload, payloads).map { protoBufFormat.decodeFromPayload(it) }
}

internal fun routePayload(route: String): Payload {
    return buildPayload {
        data(ByteReadPacket.Empty)
        metadata(RoutingMetadata(route))
    }
}
internal inline fun <reified T> ProtoBuf.encodeToPayload(route: String, value: T): Payload = buildPayload {
    data(encodeToByteArray(value))
    metadata(RoutingMetadata(route))
}
and i see in RoutingMetadata class, the mime type is
"message/x.rsocket.routing.v0", 0x7E
Spring code: Note sure if this the right piece
Copy code
private void extractEntry(ByteBuf content, @Nullable String mimeType, Map<String, Object> result) {
   if (content.readableBytes() == 0) {
      return;
   }
   EntryExtractor<?> extractor = this.registrations.get(mimeType);
   if (extractor != null) {
      extractor.extract(content, result);
      return;
   }
   if (mimeType != null && mimeType.equals(WellKnownMimeType.MESSAGE_RSOCKET_ROUTING.getString())) {
      Iterator<String> iterator = new RoutingMetadata(content).iterator();
      if (iterator.hasNext()) {
         result.put(MetadataExtractor.ROUTE_KEY, iterator.next());
      }
   }
}
which i guess it check for Message_rsocket_routing which is :
"message/x.rsocket.routing.v0", (byte) 0x7E
i have not enabled the debugger but after this function the debugger logs:
Copy code
if (logger.isDebugEnabled()) {
   logger.debug("Values extracted from metadata: " + result +
         " with registrations for " + this.registrations.keySet() + ".");
}
So i think both for simple interactions are using routing metadata? or i am missing something
o
Have you configured routing metadata in RSocketConnector on client side, like here:
Copy code
connectionConfig {
  payloadMimeType = PayloadMimeType(
    data = WellKnownMimeType.ApplicationJson, //or something different
    metadata = WellKnownMimeType.MessageRSocketRoutingMetadata
  )
}
g
I did not 😛, it seems that was the problem thank you !! You were right at first, spring by default takes in composite metadata (i was confused with the piece of code i was looking above). My connectionConfig:
Copy code
payloadMimeType= PayloadMimeType(
    data = WellKnownMimeType.ApplicationOctetStream,
    metadata = WellKnownMimeType.MessageRSocketCompositeMetadata
And in every request i have
Copy code
internal fun routePayload(route: String): Payload {
    return buildPayload {
        data(ByteReadPacket.Empty)
        compositeMetadata {
            add(RoutingMetadata(route))
        }
    }
}
o
so, now everything works?
g
yup like charm. I tested with the request channel and and request response patterns, against my springboot server.
After digging more in spring's code, i found (not 100% sure) that every interaction (except the fnf) is using the request channel one, so i though i would have to manually use likewise requestChannel pattern everywhere but i think spring handles it like magic 😛 Note: i guess spring uses everywhere request channel to because this is the only non-blocking java API?, and since in kotlin every API is a suspended one i do not have to worry about it? (prob another thread)
o
As far as I see, spring support all interactions (https://github.com/spring-projects/spring-framework/blob/4f8516e2c3ca420b1608840ab[…]work/messaging/rsocket/annotation/support/MessagingRSocket.java) but Im not a pro in spring, so I don't know concretely, which declaration will result in which request type 🙂
g
Indeed, mb mb, my phrasing is bad, by requestChannel i was refereing to the private method which spring calls almost everywhere
handleAndReply
(which is similar for me at least 😛 to the requestChannel). But at the end probably this has nothing to do with the client since it just implements properly the
RSocket
interface.