Branching pipeline

Hi,

I'm implementing a protocol which require a handshake exchange (both ways) before sending messages.
The handshake and the message require a completely different pipeline.

I made my handlers statefull with a isHandshaked property that I set when the handshake handler get its handshake. This is quite inconvenient as I need to find the statefull handlers by types which isn't easy when using multiples handlers of the same kind.

Also this means I can't use some premade handlers like ByteToMessagehandlers as there is no way to pass my state to the coder/decoder. (I made some passthrough handlers to solve this but its qui fragile)

What's the preferred way to setup branching ? I found a forum message saying it's quite common with some code extracts but I can't find a way to get it working.

Good morning @AlexisQapa,

NIO channel pipelines are mutable. However you can only remove handlers that implement the RemovableChannelHandler protocol.

If you don't want to find your handlers by type you can also find them by name. The addHandler function has an argument name: String? that is set to nil by default. Also you can remove handler by name with the removeHandler(name: String) method.

Generally speaking it is very common to mutate the channel pipeline, if the protocol communication is changed during a connections lifetime. For example: If you start in a plaintext protocol and upgrade to a TLS connection later it is perfectly reasonable to add a NIOSSLHandler to the pipeline. Another example could be using a HTTP proxy. You start with HTTP handlers and you remove them once the proxy connection is setup, then you add handlers for the protocol you need to talk to your final destination.

If the protocol stays the same, we generally recommend handling everything with the same handler and adding all the state to this one handler. If the state becomes very complicated we recommend using a state machine in your handler.

May I ask why they need completely different pipelines?

I hope that answers your questions. I'm happy to help further, if you need more help.

1 Like

Good morning,

I didn't know about RemovableChannelHandlers and your example made things more clear.
I'll update my code and report any further issue.

Well I guess one could make it a single pipeline but the handshake don't have any framing while all other messages have length prefixed framing. Handlers for this are offered by nio-extras but I couldn't find a way to make them act only on messages and not on the handshake. Now I will simply add and remove those instead of trying to make them statefull.

Thanks for your answer !

1 Like

If you implement the ByteToMessageDecoder protocol, you can also just use one of the ByteBuffer readLengthPrefixed* functions.

For example: If you have a length prefix, that is four bytes, this call will give you the message:

let message = buffer.readLengthPrefixedSlice(as: UInt32.self)

Generally I would even advice to use the NIOSingleStepByteToMessageDecoder (which makes implementing the ByteToMessageDecoder protocol simpler). However you can only use this, if you never want to emit multiple messages for a given byte.

You can see it in action in Postgres:

A very short handshake can also be seen there with the hasAlreadyReceivedBytes: Bool flag.

Hope that helps.

1 Like

Great,

I must say that diving into nio with only the doc/examples in the nio repo is challenging but your support is awesome ! (coming from iOS dev without much network framework experience)

On a side note, is the forum the preferred way to ask for questions like this ?

thanks again !

1 Like

I feel you, I used to be an iOS engineer as well. For this reason we try to provide support - as best as we can - here. However we are very excited about contributions that improve our documentation: whether that's in the forums or directly in the repos.

Yes. GitHub issues is also fine and there is a swift on server slack channel. You will support at either of those places.

3 Likes
Terms of Service

Privacy Policy

Cookie Policy