package com.dianping.pigeon.remoting.netty.codec; import com.dianping.pigeon.compress.*; import com.dianping.pigeon.remoting.common.codec.CodecConfig; import com.dianping.pigeon.remoting.common.codec.CodecConfigFactory; import com.dianping.pigeon.remoting.common.domain.generic.CompressType; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.*; import java.io.IOException; import static org.jboss.netty.buffer.ChannelBuffers.dynamicBuffer; import static org.jboss.netty.channel.Channels.write; /** * @author qi.yin * 2016/06/14 下午11:40. */ public class CompressHandler extends SimpleChannelHandler { private static Compress gZipCompress = CompressFactory.getGZipCompress(); private static Compress snappyCompress = CompressFactory.getSnappyCompress(); private CodecConfig codecConfig; public CompressHandler(CodecConfig codecConfig) { this.codecConfig = codecConfig; } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() == null || !(e.getMessage() instanceof CodecEvent)) { return; } CodecEvent codecEvent = (CodecEvent) e.getMessage(); if (codecEvent.isValid()) { if (codecEvent.isUnified()) { ChannelBuffer buffer = doUnCompress(e.getChannel(), codecEvent); codecEvent.setBuffer(buffer); } } Channels.fireMessageReceived(ctx, codecEvent, e.getRemoteAddress()); } @Override public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (!(e instanceof MessageEvent)) { ctx.sendDownstream(e); return; } MessageEvent evt = (MessageEvent) e; if (!(evt.getMessage() instanceof CodecEvent)) { ctx.sendDownstream(evt); return; } CodecEvent codecEvent = (CodecEvent) evt.getMessage(); if (codecEvent.isUnified()) { ChannelBuffer buffer = doCompress(e.getChannel(), codecEvent); codecEvent.setBuffer(buffer); write(ctx, evt.getFuture(), codecEvent, evt.getRemoteAddress()); } else { ctx.sendDownstream(e); } } private ChannelBuffer doUnCompress(Channel channel, CodecEvent codecEvent) throws IOException { ChannelBuffer frame = codecEvent.getBuffer(); byte command = frame.getByte(CodecConstants._FRONT_COMMAND_LENGTH); //compact short compress = (short) (command & 0x60); if (compress == 0x00) { return frame; } int totalLength = frame.getInt(frame.readerIndex() + CodecConstants._HEAD_LENGTH); int compressLength = totalLength - CodecConstants._HEAD_FIELD_LENGTH; byte[] in; byte[] out = null; ChannelBuffer result; switch (compress) { case 0x00: return frame; case 0x20: in = new byte[compressLength]; frame.getBytes(frame.readerIndex() + CodecConstants._FRONT_LENGTH, in); out = snappyCompress.unCompress(in); codecEvent.setIsCompress(true); break; case 0x40: in = new byte[compressLength]; frame.getBytes(frame.readerIndex() + CodecConstants._FRONT_LENGTH, in); out = gZipCompress.unCompress(in); codecEvent.setIsCompress(true); break; case 0x60: throw new IllegalArgumentException("Invalid compress type."); } int _totalLength = CodecConstants._HEAD_FIELD_LENGTH + out.length; result = channel.getConfig().getBufferFactory().getBuffer( _totalLength + CodecConstants._FRONT_LENGTH_); result.writeBytes(frame, frame.readerIndex(), CodecConstants._HEAD_LENGTH); result.writeInt(_totalLength); result.writeBytes(frame, frame.readerIndex() + CodecConstants._FRONT_LENGTH_, CodecConstants._HEAD_FIELD_LENGTH); result.writeBytes(out); return result; } private ChannelBuffer doCompress(Channel channel, CodecEvent codecEvent) throws IOException { ChannelBuffer frame = codecEvent.getBuffer(); int command = frame.getByte(CodecConstants._FRONT_COMMAND_LENGTH); //compress ChannelBuffer result = frame; int frameLength = frame.readableBytes(); if (codecConfig.isCompress(frameLength)) { CompressType compressType = codecConfig.getCompressType(); switch (compressType) { case None: command = command | 0x00; break; case Snappy: command = command | 0x20; result = doCompress0(channel, frame, frameLength, snappyCompress); break; case Gzip: command = command | 0x40; result = doCompress0(channel, frame, frameLength, gZipCompress); break; } } else { command = command | 0x00; } int oldWriteIndex = result.writerIndex(); result.writerIndex(CodecConstants._FRONT_COMMAND_LENGTH); result.writeByte(command); result.writerIndex(oldWriteIndex); return result; } private ChannelBuffer doCompress0(Channel channel, ChannelBuffer frame, int frameLength, Compress compress) throws IOException { ChannelBuffer result; int bodyLength = frameLength - CodecConstants._FRONT_LENGTH; byte[] in = new byte[bodyLength]; frame.getBytes(CodecConstants._FRONT_LENGTH, in, 0, bodyLength); byte[] out = compress.compress(in); byte[] lengthBuf = new byte[CodecConstants._HEAD_FIELD_LENGTH]; frame.getBytes(CodecConstants._FRONT_LENGTH_, lengthBuf, 0, lengthBuf.length); int totalLength = out.length + lengthBuf.length; int _frameLength = totalLength + CodecConstants._FRONT_LENGTH_; result = dynamicBuffer(_frameLength, channel.getConfig().getBufferFactory()); result.writeBytes(frame, frame.readerIndex(), CodecConstants._HEAD_LENGTH); result.writeInt(totalLength); result.writeBytes(lengthBuf); result.writeBytes(out); return result; } }