package com.pwt.netty.conponents;

import com.pwt.netty.handler.ChargerServerHandler;
import com.pwt.netty.handler.Vehicle2ServerHandler;
import com.pwt.netty.handler.WebSocketFrameHandler;
import com.pwt.netty.handler.WebSocketSecurityHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

import java.util.List;

/**
 * @author linyun
 * @version V1.0
 * @Title: SocketParser
 * @Description: socket和websocket协议解析
 * @date 2022/11/11
 **/
public class SocketParser extends ByteToMessageDecoder {

    /* 默认暗号长度为23 */
    private static final int MAX_LENGTH = 23;

    /* WebSocket握手的协议前缀 */
    private static final String WEBSOCKET_PREFIX = "GET /";

    /* websocket请求前缀 **/
    public static final String WEBSOCKET_PATH = "/websocket";

    /**
     * @Description: 根据数据头自动匹配对应的协议
     * @Author: linyun
     * @Date: 2022/11/11 15:38
     * @Param:[ctx, byteBuf, list]
     * @Return:void
     **/
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception
    {
        // 如果是websocket协议,path前缀包含:GET /
        String protocol = getBufStart(byteBuf);
        if (protocol.startsWith(WEBSOCKET_PREFIX))
        {
            // 增加HttpServerCodec,将请求和应答消息解码为http消息
            ctx.pipeline().addLast(new HttpServerCodec());
            // 增加HttpObjectAggregator,目的是将http消息的多个部分组合成一条完整的消息
            ctx.pipeline().addLast(new HttpObjectAggregator(65536));
            // 用于大数据的分区传输
            ctx.pipeline().addLast(new ChunkedWriteHandler());
            // WebSocket 数据压缩扩展
            ctx.pipeline().addLast(new WebSocketServerCompressionHandler());
            // websocket认证处理类
            ctx.pipeline().addLast(new WebSocketSecurityHandler());
            // WebSocket 握手、控制帧处理;(注意该handler是将http协议握手升级为webSocket,故该handler需要在token验证之后,并且需要将消息传递为下一业务handler)
            ctx.pipeline().addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
            // 通道业务处理handler
            ctx.pipeline().addLast(new WebSocketFrameHandler());
            // 移除socket 相关的处理类
        }
        // 读指针重置
        byteBuf.resetReaderIndex();
        ctx.pipeline().remove(this.getClass());
    }

    /**
     * 获取协议头
     **/
    private String getBufStart(ByteBuf in)
    {
        int length = in.readableBytes();
        if (length > MAX_LENGTH)
        {
            length = MAX_LENGTH;
        }
        // 标记读位置
        in.markReaderIndex();
        byte[] content = new byte[length];
        in.readBytes(content);
        return new String(content);
    }
}
