package com.wecloud.im.netty.core;

import com.wecloud.im.ws.model.WsConstants;
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.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

import static com.wecloud.im.ws.ImConstant.READER_IDLE_TIME;

@Component
public class NettyChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Resource
    private ChannelInboundHandler channelInboundHandler;

    public static final String SINGLE_HTTP_REQUEST_HANDLER = "SingleHttpRequestHandler";

    public static final String APP_WEB_SOCKET_SERVEROTOCOL_HANDLER = "appWebSocketServerotocolHandler";

    public static final int MAX_CONTENT_LENGTH = 2048576000;


    @Override
    protected void initChannel(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        // http
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new ChunkedWriteHandler());
        pipeline.addLast(new HttpObjectAggregator(MAX_CONTENT_LENGTH));

        // 服务端api接口
        pipeline.addLast(SINGLE_HTTP_REQUEST_HANDLER, channelInboundHandler);

        // 连接超时管理 (判断通道是否有数据写入)
//        pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(60));

        // "/appws"路径 升级长连接
        pipeline.addLast(APP_WEB_SOCKET_SERVEROTOCOL_HANDLER, new WebSocketServerProtocolHandler(WsConstants.WS_URL));

        /*
         * 心跳机制
         * observeOutput -当评估写空闲时是否应该考虑字节的消耗。默认为false。
         * readerIdleTime—状态为IdleState的IdleStateEvent。当在指定的时间内没有执行读操作时，将触发READER_IDLE。指定0禁用。
         * writerIdleTime—状态为IdleState的IdleStateEvent。当在指定的时间内没有执行写操作时，会触发WRITER_IDLE。指定0禁用。
         * allIdleTime—状态为IdleState的IdleStateEvent。在一定时间内不读不写会触发ALL_IDLE。指定0禁用。
         * unit—readerIdleTime、writeIdleTime和allIdleTime的时间单位
         */
        pipeline.addLast(new IdleStateHandler(READER_IDLE_TIME, 0, 0, TimeUnit.SECONDS));
    }

}
