/*
  * 接收
  *
  * @param context 上下文
  * @param channel 通道
  * @param buffer 缓存
  * @param readable 缓存可读
  * @param bytes 输入缓存
  * @param offset 指向已读数据的偏移量,off之前的数据都是已用过的
  * @param limit 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的数据
  * @return 后续动作
  * @throws IOException
  */
 private NextAction receive(
     FilterChainContext context,
     Channel channel,
     Buffer buffer,
     int readable,
     byte[] bytes,
     int offset,
     int limit)
     throws IOException {
   for (; ; ) {
     int read = Math.min(readable, bytes.length - limit); // 取bytes缓存空闲区,和可读取新数据,的最小值,即:此次最多读写数据的大小
     buffer.get(bytes, limit, read); // 从可读取新数据中,读取数据,尽量填满bytes缓存空闲区
     limit += read; // 有效数据变长
     readable -= read; // 可读数据变少
     UnsafeByteArrayInputStream input =
         new UnsafeByteArrayInputStream(
             bytes, offset, limit - offset); // 将bytes缓存转成InputStream,不需要关闭
     Object msg = upstreamCodec.decode(channel, input); // 调用Codec接口,解码数据
     if (msg == Codec.NEED_MORE_INPUT) { // 如果Codec觉得数据不够,不足以解码成一个对象
       if (readable == 0) { // 如果没有更多可读数据
         channel.setAttribute(
             BUFFER_KEY, new Object[] {bytes, offset, limit}); // 放入通道属性中,等待下一个Buffer的到来
         return context.getStopAction();
       } else { // 扩充或挪出空闲区,并循环,直到可读数据都加载到bytes缓存
         if (offset == 0) { // 如果bytes缓存全部没有被使用,如果这时数据还不够
           bytes = Bytes.copyOf(bytes, bytes.length << 1); // 将bytes缓存扩大一倍
         } else { // 如果bytes缓存有一段数据已被使用
           int len = limit - offset; // 计算有效数据长度
           System.arraycopy(
               bytes, offset, bytes, 0, len); // 将数据向前移到,压缩到已使用的部分,这样limit后面就会多出一些空闲,可以放数据
           offset = 0; // 移到后,bytes缓存没有数据被使用
           limit = len; // 移到后,有效数据都在bytes缓存最前面
         }
       }
     } else { // 如果解析出一个结果
       int position = input.position(); // 记录InputStream用了多少
       if (position == offset) { // 如果InputStream没有被读过,就返回了数据,直接报错,否则InputStream永远读不完,会死递归
         throw new IOException("Decode without read data.");
       }
       offset = position; // 记录已读数据
       context.setMessage(msg); // 将消息改为解码后的对象,以便被后面的Filter使用。
       if (limit - offset > 0 || readable > 0) { // 如果有效数据没有被读完,或者Buffer区还有未读数据
         return context.getInvokeAction(
             new Object[] {
               buffer, readable, bytes, offset, limit
             }); // 正常执行完Filter,并重新发起一轮Filter,继续读
       } else { // 否则所有数据读完
         return context.getInvokeAction(); // 正常执行完Filter
       }
     }
   }
 }
 @Override
 protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out)
     throws Exception {
   int readable = input.readableBytes();
   if (readable <= 0) {
     return;
   }
   int off, limit;
   byte[] buf = mBuffer;
   if (buf == null) {
     buf = new byte[bufferSize];
     off = limit = 0;
   } else {
     off = mOffset;
     limit = mLimit;
   }
   com.antrou.dubbo.remoting.netty4.NettyChannel channel =
       com.antrou.dubbo.remoting.netty4.NettyChannel.getOrAddChannel(
           ctx.channel(), url, handler);
   boolean remaining = true;
   Object msg;
   UnsafeByteArrayInputStream bis;
   try {
     do {
       // read data into buffer.
       int read = Math.min(readable, buf.length - limit);
       input.readBytes(buf, limit, read);
       limit += read;
       readable -= read;
       bis = new UnsafeByteArrayInputStream(buf, off, limit - off);
       // decode object.
       do {
         try {
           msg = codec.decode(channel, bis);
         } catch (IOException e) {
           remaining = false;
           throw e;
         }
         if (msg == Codec.NEED_MORE_INPUT) {
           if (off == 0) {
             if (readable > 0) {
               buf = Bytes.copyOf(buf, buf.length << 1);
             }
           } else {
             int len = limit - off;
             System.arraycopy(buf, off, buf, 0, len); // adjust buffer.
             off = 0;
             limit = len;
           }
           break;
         } else {
           int pos = bis.position();
           if (off == pos) {
             remaining = false;
             throw new IOException("Decode without read data.");
           }
           if (msg != null) {
             out.add(msg);
           }
           off = pos;
         }
       } while (bis.available() > 0);
     } while (readable > 0);
   } finally {
     if (remaining) {
       int len = limit - off;
       if (len < buf.length / 2) {
         System.arraycopy(buf, off, buf, 0, len);
         off = 0;
         limit = len;
       }
       mBuffer = buf;
       mOffset = off;
       mLimit = limit;
     } else {
       mBuffer = null;
       mOffset = mLimit = 0;
     }
     com.antrou.dubbo.remoting.netty4.NettyChannel.removeChannelIfDisconnected(ctx.channel());
   }
 }