Use JSONDecoder with ByteBuffer

Hi, I'm currently working on a TCP server using SwiftNIO, and I can't find an easy way to convert a ByteBuffer directly to Data in order to decode it more easily. Here is my inbound handler tasked with parsing the received messages:

final class MessageParser: ChannelInboundHandler {
    typealias InboundIn = ByteBuffer
    typealias InboundOut = CommsMessage
    
    public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        do {
            var buffer = self.unwrapInboundIn(data)
            let bytes = buffer.readBytes(length: buffer.readableBytes)!
            var data = Data()
            data.append(contentsOf: bytes)
            let message = try decoder.decode(CommsMessage.self, from: data)
            context.fireChannelRead(self.wrapInboundOut(message))
        }catch {
            logger.error(error.localizedDescription)
        }
    }
}

This seems unnecessarily cumbersome, there must be a more efficient way of doing this that I'm not aware of...
Is there a better way to decode a ByteBuffer using JSONDecoder ?

1 Like

I don't use NIO, but a quick look through the code shows that you can convert it directly--i.e., Data(buffer):

Is that what you're looking for?

2 Likes

Yes, but it doesn't seem to be accessible even if it's declared public in the source code e.g:

let buffer = self.unwrapInboundIn(data)
let data = buffer.readData(length: buffer.readableBytes, byteTransferStrategy: ByteBuffer.ByteTransferStrategy.automatic)
let message = try decoder.decode(CommsMessage.self, from: data)

Will result in:

    error: value of type 'MessageParser.InboundIn' (aka 'ByteBuffer') has no member 'readData'
            let data = buffer.readData(length: buffer.readableBytes, byteTransferStrategy: ByteBuffer.ByteTransferStrategy.automatic)
    error: type 'ByteBuffer' has no member 'ByteTransferStrategy'
            let data = buffer.readData(length: buffer.readableBytes, byteTransferStrategy: ByteBuffer.ByteTransferStrategy.automatic)

The same goes for the Data initialiser

Do I need to import anything else besides NIO ?

Never mind I had to import NIOFoundationCompat. I found out it was in a separate module after reading the comments at the top of ByteBuffer-foundation.swift. Thanks @xwu for the help !

2 Likes

@RobertBerglund, It looks like you don't even need to convert ByteBuffer to Data: JSONDecoder Extension Reference

2 Likes

That’s even better, thanks!

I have a Codable struct with a ByteBuffer property. Adding import NIOFoundationCompat didn't change anything, it just says, that the struct doesn't conform to Codable. Am I doing something wrong?