com.github.netty.protocol.nrpc.codec.RpcDecoder Maven / Gradle / Ivy
package com.github.netty.protocol.nrpc.codec;
import com.github.netty.protocol.nrpc.RpcPacket;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.ReferenceCountUtil;
import static com.github.netty.core.util.IOUtil.BYTE_LENGTH;
import static com.github.netty.core.util.IOUtil.INT_LENGTH;
import static com.github.netty.protocol.nrpc.RpcPacket.RequestPacket;
import static com.github.netty.protocol.nrpc.RpcPacket.ResponsePacket;
import static com.github.netty.protocol.nrpc.codec.RpcEncoder.PROTOCOL_HEADER;
import static com.github.netty.protocol.nrpc.codec.RpcEncoder.RPC_CHARSET;
/**
* RPC decoder
*
*
* Request Packet (note: 1 = request type)
* -+------8B--------+--1B--+--1B--+------4B------+-----4B-----+-----4B-----+------1B--------+-----length-----+------1B-------+---length----+-----4B------+-------length-------------+
* | header/version | type | ACK | total length | Request ID| timeout/ms | service length | service name | method length | method name | data length | data |
* | NRPC/010 | 1 | 1 | 55 | 1 | 1000 | 8 | "/sys/user" | 7 | getUser | 24 | {"age":10,"name":"wang"} |
* -+----------------+------+------+--------------+------------+------------+----------------+----------------+---------------+-------------+-------------+--------------------------+
*
*
* Response Packet (note: 2 = response type)
* -+------8B--------+--1B--+--1B--+------4B------+-----4B-----+---2B---+--------1B------+--length--+---1B---+-----4B------+----------length----------+
* | header/version | type | ACK | total length | Request ID | status | message length | message | encode | data length | data |
* | NRPC/010 | 2 | 0 | 35 | 1 | 200 | 2 | ok | 1 | 24 | {"age":10,"name":"wang"} |
* -+----------------+------+------+--------------+------------+--------+----------------+----------+--------+-------------+--------------------------+
*
* @author wangzihao
*/
public class RpcDecoder extends LengthFieldBasedFrameDecoder {
private static final byte[] EMPTY = {};
private static final int LENGTH_FIELD_OFFSET = PROTOCOL_HEADER.length + BYTE_LENGTH + BYTE_LENGTH;
public RpcDecoder() {
this(10 * 1024 * 1024);
}
public RpcDecoder(int maxLength) {
super(maxLength,
// header | type | ACK
LENGTH_FIELD_OFFSET,
INT_LENGTH,
0,
0,
true);
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
ByteBuf msg = (ByteBuf) super.decode(ctx, buffer);
if (msg == null) {
return null;
}
try {
return decodeToPojo(msg);
} finally {
if (msg.refCnt() > 0) {
ReferenceCountUtil.safeRelease(msg);
}
}
}
/**
* Resolve to the entity class
*
* @param msg msg
* @return
*/
protected Object decodeToPojo(ByteBuf msg) {
//Skip protocol header
msg.skipBytes(PROTOCOL_HEADER.length);
byte rpcType = msg.readByte();
byte ack = msg.readByte();
//read total length
long totalLength = msg.readUnsignedInt();
long totalPacketLength = totalLength + LENGTH_FIELD_OFFSET;
switch (rpcType) {
case RpcPacket.TYPE_CLIENT_REQUEST: {
RequestPacket packet = RequestPacket.newInstance();
packet.setPacketLength(totalPacketLength);
//Ack
packet.setAck(ack);
//Request ID
packet.setRequestId(msg.readInt());
//Request Timeout
packet.setTimeout(msg.readInt());
//Request service name
packet.setRequestMappingName(msg.readCharSequence(msg.readUnsignedByte(), RPC_CHARSET).toString());
//Request service version
packet.setVersion(msg.readCharSequence(msg.readUnsignedByte(), RPC_CHARSET).toString());
//Request method
packet.setMethodName(msg.readCharSequence(msg.readUnsignedByte(), RPC_CHARSET).toString());
//Request data
long dataLength = msg.readUnsignedInt();
if (dataLength > 0) {
packet.setData(new byte[(int) dataLength]);
msg.readBytes(packet.getData());
} else {
packet.setData(EMPTY);
}
return packet;
}
case RpcPacket.TYPE_RESPONSE_CHUNK_ACK:
case RpcPacket.TYPE_RESPONSE_CHUNK:
case RpcPacket.TYPE_RESPONSE_LAST: {
ResponsePacket packet = ResponsePacket.newInstance(rpcType);
packet.setPacketLength(totalPacketLength);
//Ack
packet.setAck(ack);
//Request ID
packet.setRequestId(msg.readInt());
//Response status
packet.setStatus(msg.readUnsignedShort());
//Response encode
packet.setEncode(DataCodec.Encode.indexOf(msg.readUnsignedByte()));
//Response information
packet.setMessage(msg.readCharSequence(msg.readUnsignedByte(), RPC_CHARSET).toString());
//Request data
long dataLength = msg.readUnsignedInt();
if (dataLength > 0) {
packet.setData(new byte[(int) dataLength]);
msg.readBytes(packet.getData());
} else {
packet.setData(null);
}
//Chunk id
if (packet instanceof RpcPacket.ResponseChunkPacket) {
((RpcPacket.ResponseChunkPacket) packet).setChunkId(msg.readUnsignedShort());
} else if (packet instanceof RpcPacket.ResponseChunkAckPacket) {
((RpcPacket.ResponseChunkAckPacket) packet).setAckChunkId(msg.readUnsignedShort());
}
return packet;
}
default: {
RpcPacket packet = new RpcPacket(rpcType);
packet.setPacketLength(totalPacketLength);
//ack
packet.setAck(ack);
//data
if (totalLength > 0) {
packet.setData(new byte[(int) totalLength]);
msg.readBytes(packet.getData());
} else {
packet.setData(null);
}
return packet;
}
}
}
}