package redis.server.netty; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ReplayingDecoder; import redis.netty4.Command; import java.io.IOException; import java.util.List; import static redis.netty4.RedisReplyDecoder.readLong; /** * Decode commands. */ public class RedisCommandDecoder extends ReplayingDecoder<Void> { private byte[][] bytes; private int arguments = 0; @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (bytes != null) { int numArgs = bytes.length; for (int i = arguments; i < numArgs; i++) { if (in.readByte() == '$') { long l = readLong(in); if (l > Integer.MAX_VALUE) { throw new IllegalArgumentException("Java only supports arrays up to " + Integer.MAX_VALUE + " in size"); } int size = (int) l; bytes[i] = new byte[size]; in.readBytes(bytes[i]); if (in.bytesBefore((byte) '\r') != 0) { throw new RedisException("Argument doesn't end in CRLF"); } in.skipBytes(2); arguments++; checkpoint(); } else { throw new IOException("Unexpected character"); } } try { out.add(new Command(bytes)); } finally { bytes = null; arguments = 0; } } else if (in.readByte() == '*') { long l = readLong(in); if (l > Integer.MAX_VALUE) { throw new IllegalArgumentException("Java only supports arrays up to " + Integer.MAX_VALUE + " in size"); } int numArgs = (int) l; if (numArgs < 0) { throw new RedisException("Invalid size: " + numArgs); } bytes = new byte[numArgs][]; checkpoint(); decode(ctx, in, out); } else { // Go backwards one in.readerIndex(in.readerIndex() - 1); // Read command -- can't be interupted byte[][] b = new byte[1][]; b[0] = in.readBytes(in.bytesBefore((byte) '\r')).array(); in.skipBytes(2); out.add(new Command(b, true)); } } }