package com.lsbc.game.server.handler;
import com.google.protobuf.MessageLite;
import com.google.protobuf.MessageLiteOrBuilder;
import com.lsbc.game.pojo.constant.ParatrooperConstant;
import com.lsbc.game.protobuf.RequestParamMsg;
import com.lsbc.hornet.auth.SpringContextUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
public class PortUnificationServerHandler extends ByteToMessageDecoder {
private NettyServerHandler nettyServerHandler= (NettyServerHandler)SpringContextUtils.getBean("nettyServerHandler");
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
if (byteBuf.readableBytes() < 5) {
return;
}
final int magic1 = byteBuf.getUnsignedByte(byteBuf.readerIndex());
final int magic2 = byteBuf.getUnsignedByte(byteBuf.readerIndex() + 1);
if (isHttp(magic1, magic2)) {
log.info("this is a http msg");
switchToHttp(channelHandlerContext);
} else {
log.info("this is a socket msg");
switchToTcp(channelHandlerContext);
}
}
private void switchToHttp(ChannelHandlerContext ctx) {
ChannelPipeline pipeline = ctx.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler("/", null, true));
pipeline.addLast(new MessageToMessageDecoder<WebSocketFrame>() {
@Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> out) throws Exception {
if (frame instanceof TextWebSocketFrame) {
log.info("文本帧消息:" + ((TextWebSocketFrame) frame).text());
}
else if (frame instanceof BinaryWebSocketFrame) {
BinaryWebSocketFrame binaryWebSocketFrame = (BinaryWebSocketFrame) frame;
byte[] by = new byte[frame.content().readableBytes()];
binaryWebSocketFrame.content().readBytes(by);
ByteBuf bytebuf = Unpooled.buffer();
bytebuf.writeBytes(by);
out.add(bytebuf);
} else if (frame instanceof PingWebSocketFrame) {
log.info("其它帧消息" + frame.toString());
}
}
});
pipeline.addLast(new MessageToMessageEncoder<MessageLiteOrBuilder>() {
@Override
protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out) throws Exception {
ByteBuf result = null;
if (msg instanceof MessageLite) {
result = Unpooled.wrappedBuffer(((MessageLite) msg).toByteArray());
}
if (msg instanceof MessageLite.Builder) {
result = Unpooled.wrappedBuffer(((MessageLite.Builder) msg).build().toByteArray());
}
WebSocketFrame frame = new BinaryWebSocketFrame(result);
out.add(frame);
}
});
pipeline.addLast(new IdleStateHandler(ParatrooperConstant.NettyConstant.SERVER_READER_IDLE_TIME, ParatrooperConstant.NettyConstant.SERVER_WRITER_IDLE_TIME, ParatrooperConstant.NettyConstant.SERVER_ALL_IDLE_TIME, TimeUnit.SECONDS));
pipeline.addLast(new ProtobufDecoder(RequestParamMsg.RequestParam.getDefaultInstance()));
pipeline.addLast(nettyServerHandler);
pipeline.remove(this);
}
private boolean isHttp(int magic1, int magic2) {
return magic1 == 'G' && magic2 == 'E' ||
magic1 == 'P' && magic2 == 'O' ||
magic1 == 'P' && magic2 == 'U' ||
magic1 == 'H' && magic2 == 'E' ||
magic1 == 'O' && magic2 == 'P' ||
magic1 == 'P' && magic2 == 'A' ||
magic1 == 'D' && magic2 == 'E' ||
magic1 == 'T' && magic2 == 'R' ||
magic1 == 'C' && magic2 == 'O';
}
private void switchToTcp(ChannelHandlerContext ctx) {
ChannelPipeline pipeline = ctx.pipeline();
pipeline.addLast(new IdleStateHandler(ParatrooperConstant.NettyConstant.SERVER_READER_IDLE_TIME, ParatrooperConstant.NettyConstant.SERVER_WRITER_IDLE_TIME, ParatrooperConstant.NettyConstant.SERVER_ALL_IDLE_TIME, TimeUnit.SECONDS));
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(RequestParamMsg.RequestParam.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(nettyServerHandler);
pipeline.remove(this);
}
}
|