package com.manning.nettyinaction.chapter14; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.util.CharsetUtil; import java.util.List; public class MemcachedResponseDecoder extends ByteToMessageDecoder { private enum State { Header, Body } private State state = State.Header; private int totalBodySize; private byte magic; private byte opCode; private short keyLength; private byte extraLength; private short status; private int id; private long cas; @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { switch (state) { case Header: if (in.readableBytes() < 24) { return;//response header is 24 bytes } magic = in.readByte(); opCode = in.readByte(); keyLength = in.readShort(); extraLength = in.readByte(); in.skipBytes(1); status = in.readShort(); totalBodySize = in.readInt(); id = in.readInt(); //referred to in the protocol spec as opaque cas = in.readLong(); state = State.Body; case Body: if (in.readableBytes() < totalBodySize) { return; //until we have the entire payload return } int flags = 0, expires = 0; int actualBodySize = totalBodySize; if (extraLength > 0) { flags = in.readInt(); actualBodySize -= 4; } if (extraLength > 4) { expires = in.readInt(); actualBodySize -= 4; } String key = ""; if (keyLength > 0) { ByteBuf keyBytes = in.readBytes(keyLength); key = keyBytes.toString(CharsetUtil.UTF_8); actualBodySize -= keyLength; } ByteBuf body = in.readBytes(actualBodySize); String data = body.toString(CharsetUtil.UTF_8); out.add(new MemcachedResponse( magic, opCode, status, id, cas, flags, expires, key, data )); state = State.Header; } } }