package com.sjyt.icom.asst.server;

import com.sjyt.icom.asst.conf.properties.WebSocketProperties;
import com.sjyt.icom.asst.context.handle.netty.WebSocketHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
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.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * WebSocket通道连接初始化
 *
 * <p>ChannelInitializer自身也是一个ChannelHandler,
 * 一开始会被注册到ChannelPipeline里，但是在初始化(initChannel)完成后，ChannelInitializer会将自己从pipeline中移除。
 * HttpServerCodec: 内置的ChannelHandler，集成了HttpRequest解码器以及HttpResponse编码器。 HttpObjectAggregator:
 * 内置的ChannelHandler, 将HttpMessage和HttpContent集合成FullHttpRequest。 ChunkedWriteHandler:
 * 内置的ChannelHandler, 实现大数据包的传输。 IdleStateHandler: 内置的ChannelHandler,
 * 读、写空闲处理器，空闲超时会触发一个IdleStateEvent事件。我们可以通过接受IdleStateEvent事件后会发送PING消息，实现Websocket服务的PING/PONG机制。
 * HandshakeHandler: 自定义的ChannelHandler,
 * 接受一个FullHttpRequest对象，处理连接的认证，完成连接的升级以及注册websocket的编码/解码器。Netty有内置的Websocket协议处理器WebSocketServerProtocolHandler，但是没有暴露连接认证的接口；当然我们可以使用WebSocketServerProtocolHandler，再写一个接受FullHttpRequest对象的ChannelHandler来进行连接的认证。
 * PongFrameHandler: 自定义的ChannelHandler, 接受TextWebSocketFrame对象，处理客户端的PONG消息。 TextMessageHandler:
 * 自定义的ChannelHandler, 接受TextWebSocketFrame对象，处理其他文本事件。 InnerEventHandler: 自定义ChannelHandler,
 * 处理内置的事件，如：channelInactive，IdleStateEvent。 BinaryWebsocketFrame：发送二进制信息 CloseWebsocketFrame：关闭
 * PingWebSocketFrame：心跳检测 PongWebSocketFrame:接收心跳检测 TextWebSocketFrame:发送文本信息
 *
 * @author renyanru
 * @version V1.0.0
 * @date 2022/5/27 10:13
 */
@Component
public class NioWebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
  @Autowired private WebSocketProperties webSocketProperties;
  @Resource private WebSocketHandler webSocketHandler;

  @Override
  protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    // websocket协议本身是基于http协议的，所以这边也要使用http解编码器
    pipeline.addLast(new HttpServerCodec());
    // 以块的方式来写的处理器
    pipeline.addLast(new ChunkedWriteHandler());
    pipeline.addLast(new HttpObjectAggregator(8192));
    // 心跳
    pipeline.addLast(new IdleStateHandler(5, -1, -1));
    pipeline.addLast(webSocketHandler);
    pipeline.addLast(
        new WebSocketServerProtocolHandler(webSocketProperties.getPath(), null, true, 65536));
  }
}
