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

com.envisioniot.sub.client.internal.netty.ClientEncoder Maven / Gradle / Ivy

There is a newer version: 3.0.3
Show newest version
package com.envisioniot.sub.client.internal.netty;

import com.envisioniot.sub.common.generated.Common;
import com.envisioniot.sub.common.model.Pair;
import com.envisioniot.sub.common.netty.RegManager;
import com.envisioniot.sub.common.netty.TransferVer;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.MessageLite;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.apache.log4j.Logger;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import static io.netty.buffer.Unpooled.wrappedBuffer;

/**
 */
public class ClientEncoder extends MessageToByteEncoder {
    private static Logger LOG = Logger.getLogger("ClientEncoder");
    private static final int ZIPLEN = 50;

    @Override
    protected void encode(final ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
        Class cls = msg.getClass();
        if (LOG.isDebugEnabled()) {
            LOG.info("===> encode msg class:"+ cls+", msg:"+msg);
        }

        ByteBuf buf;
        String msgName;
        if (cls == byte[].class) {
            buf = wrappedBuffer((byte[]) msg);
            msgName = "kvPair/alert";
        } else {
            Integer cmdId = null;
            MessageLite send = null;

            if (cls == Pair.class) {
                @SuppressWarnings("unchecked")
                Pair pair = (Pair) msg;
                cmdId = pair.first;
                if (cmdId == null) {
                    LOG.warn("send cmdId is null");
                    return;
                }
                send = pair.second;
            } else {
                cmdId = RegManager.getEncoderCmd(cls);
                if (cmdId == null) {
                    LOG.warn("not found cmd for cls(" + cls + ")");
                    return;
                }

                send = (MessageLite) msg;
            }

            buf = getBuf(ctx, cmdId, send);
            msgName = "cmd#" + String.valueOf(cmdId);
        }

        writeBuf(out, buf);
    }

    private ByteBuf getBuf(ChannelHandlerContext ctx, int cmdId, MessageLite send) {
        ByteString data = send == null ? ByteString.EMPTY : send.toByteString();
        int ver = TransferVer.getChannelVer(ctx);
        // 小于50B,不压缩
        boolean zip = ver < 1 ? false : needZip(data);
        ByteString d = zip ? getCompressData(data) : data;
        ByteBuf buf = wrappedBuffer(Common.TransferPkg.newBuilder().setSeqId(0).setCmdId(cmdId).setData(d).setZip(zip)
                .setVer(ver).build().toByteArray());
        return buf;
    }

    public static boolean needZip(ByteString data) {
        return data.size() > ZIPLEN;
    }

    public static ByteString getCompressData(ByteString data) {
        // TODO: if data is empty byte string.
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            GZIPOutputStream output = new GZIPOutputStream(baos);
            output.write(data.toByteArray());
            output.finish();
            output.close();

            return ByteString.copyFrom(baos.toByteArray());

        } catch (Exception e) {
            LOG.warn("", e);
            return ByteString.EMPTY;
        }
    }

    private void writeBuf(ByteBuf out, ByteBuf buf) throws IOException {
        int bodyLen = buf.readableBytes();
        int headerLen = CodedOutputStream.computeRawVarint32Size(bodyLen);

        out.ensureWritable(headerLen + bodyLen);

        CodedOutputStream headerOut = CodedOutputStream.newInstance(new ByteBufOutputStream(out), headerLen);
        headerOut.writeRawVarint32(bodyLen);
        headerOut.flush();

        out.writeBytes(buf, buf.readerIndex(), bodyLen);
    }
}