All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hyf.hotrefresh.remoting.message.MessageCodec Maven / Gradle / Ivy

package com.hyf.hotrefresh.remoting.message;

import com.hyf.hotrefresh.common.Log;
import com.hyf.hotrefresh.remoting.constants.RemotingConstants;
import com.hyf.hotrefresh.remoting.exception.CodecException;
import com.hyf.hotrefresh.remoting.rpc.RpcMessage;
import com.hyf.hotrefresh.remoting.rpc.RpcMessageFactory;
import com.hyf.hotrefresh.remoting.rpc.enums.RpcMessageCodec;
import com.hyf.hotrefresh.remoting.rpc.enums.RpcMessageCompression;
import com.hyf.hotrefresh.remoting.rpc.enums.RpcMessageEncoding;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;

/**
 * @author baB_hyf
 * @date 2022/05/14
 */
public class MessageCodec {

    // magic(x byte)
    // version(1byte)
    // message length(4byte)
    // id(4byte)
    // encoding(1byte)
    // codec(1byte)
    // compress(1byte)
    // message type(1byte)
    // header length(4byte)
    // header data
    // data body length(4byte)
    // data body

    // HYF
    public static final byte[] MAGIC = {(byte) 0x48, (byte) 0x59, (byte) 0x46};

    public static final int FIXED_LENGTH = MAGIC.length + 1 + 4 + 4 + 1 + 1 + 1 + 1 + 4 + 4;

    public static byte[] encode(Message message) {
        if (message == null) {
            throw new IllegalArgumentException("message is null");
        }

        try {
            RpcMessage rpcMessage = (RpcMessage) message.getBody();

            RpcMessageCodec codec = RpcMessageCodec.getCodec(message.getCodec());
            RpcMessageEncoding encoding = RpcMessageEncoding.getEncoding(message.getEncoding());
            RpcMessageCompression compression = RpcMessageCompression.getCompression(message.getCompress());

            // header
            Map headMap = message.getHeaderMap();
            byte[] headerData = encodeObject(headMap, encoding, codec);
            headerData = compression.compress(headerData);

            // body
            byte[] data = new byte[0];
            if (rpcMessage != null) {
                ByteBuffer buf = rpcMessage.encode(encoding, codec);
                data = buf.array();
            }
            data = compression.compress(data);

            if (FIXED_LENGTH + headerData.length + data.length > Integer.MAX_VALUE) {
                throw new CodecException("Message size reaches limit");
            }

            int messageLength = FIXED_LENGTH + headerData.length + data.length;
            ByteBuffer buf = ByteBuffer.allocate(messageLength);
            buf.put(MAGIC);
            buf.put(RemotingConstants.MESSAGE_VERSION);
            buf.putInt(messageLength);
            buf.putInt(message.getId());
            buf.put(message.getEncoding());
            buf.put(message.getCodec());
            buf.put(message.getCompress());
            buf.put(message.getMessageType());
            buf.putInt(headerData.length);
            buf.put(headerData);
            buf.putInt(data.length);
            buf.put(data);
            return buf.array();
        } catch (Exception e) {
            Log.error("Failed to encode message: " + message.toString(), e);
            throw e;
        }
    }

    public static Message decode(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            throw new IllegalArgumentException("bytes is null");
        }

        try {
            ByteBuffer buf = ByteBuffer.wrap(bytes);

            byte[] magic = new byte[MAGIC.length];
            buf.get(magic);
            if (!Arrays.equals(magic, MAGIC)) {
                throw new CodecException("Unknown message");
            }

            byte version = buf.get();
            if (version != RemotingConstants.MESSAGE_VERSION) {
                throw new CodecException("Unknown message version: " + version);
            }

            int messageLength = buf.getInt();

            int id = buf.getInt();

            byte encodingCode = buf.get();
            RpcMessageEncoding encoding = RpcMessageEncoding.getEncoding(encodingCode);
            byte codecCode = buf.get();
            RpcMessageCodec codec = RpcMessageCodec.getCodec(codecCode);
            byte compressionCode = buf.get();
            RpcMessageCompression compression = RpcMessageCompression.getCompression(compressionCode);
            byte messageTypeCode = buf.get();

            // header
            int headerLength = buf.getInt();
            byte[] headerData = new byte[headerLength];
            buf.get(headerData);
            headerData = compression.decompress(headerData);
            Map headerMap = decodeObject(headerData, encoding, codec);

            // body
            int bodyLength = buf.getInt();
            byte[] data = new byte[bodyLength];
            buf.get(data);
            data = compression.decompress(data);

            RpcMessage rpcMessage = RpcMessageFactory.createRpcMessage(messageTypeCode);
            ByteBuffer dataBuf = ByteBuffer.wrap(data);
            rpcMessage.decode(dataBuf, encoding, codec);

            Message message = MessageFactory.createEmptyMessage();
            message.setEncoding(encodingCode);
            message.setCodec(codecCode);
            message.setCompress(compressionCode);
            message.setMessageType(messageTypeCode);
            message.setHeaderMap(headerMap);
            message.setBody(rpcMessage);
            return message;
        } catch (Exception e) {
            Log.error("Failed to decode message: " + Arrays.toString(bytes), e);
            throw e;
        }
    }

    public static byte[] encodeObject(Object obj, RpcMessageEncoding encoding, RpcMessageCodec codec) {
        if (obj == null) {
            return new byte[0];
        }

        RpcMessageCodec.JdkCodec jdkCodec = new RpcMessageCodec.JdkCodec();
        return jdkCodec.encode(obj);
    }

    public static  T decodeObject(byte[] data, RpcMessageEncoding encoding, RpcMessageCodec codec) {
        if (data == null || data.length == 0) {
            return null;
        }

        RpcMessageCodec.JdkCodec jdkCodec = new RpcMessageCodec.JdkCodec();
        return jdkCodec.decode(data);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy