package com.sv.netty.netty;

import com.google.common.collect.Maps;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import static io.netty.channel.ChannelOption.TCP_NODELAY;

/**
 * netty启动服务
 *
 * @Author peakren
 * @Date 03/05/2017 6:18 PM
 */
@Component
public class BootService {

    private Logger logger = LoggerFactory.getLogger(BootService.class);

    private volatile EventLoopGroup workerGroup;
    private volatile EventLoopGroup bossGroup;
    private volatile ServerBootstrap bootstrap;
    private ChannelFuture serverChannelFuture;

    /**
     * 启动netty的控制线程
     */
    private Executor messageExecutor;

    /**
     * 下面几个是由spring注入
     */
    @Value("${netty.port}")
    private int port;

    @Value("${so.keepalive}")
    private Boolean keepalive;

    @Value("${so.backlog}")
    private int backlog;

    @Value("${tcp_nodelay}")
    private boolean nodelay;

    @Value("${so.reuseaddr}")
    private boolean reuseaddr;

    @Value("${boss.thread.count}")
    private int bossCount;

    @Value("${worker.thread.count}")
    private int workerCount;

    private Map<ChannelOption, Object> channelOptions;

    @Autowired
    private ChannelHandler channelHandler;

    /**
     * 初始化netty启动配置
     */
    public void init() {
        workerGroup = new NioEventLoopGroup();
        bossGroup = new NioEventLoopGroup();
        channelOptions = Maps.newHashMap();
        try {
            channelOptions.put(ChannelOption.SO_KEEPALIVE,keepalive);
            channelOptions.put(ChannelOption.SO_BACKLOG,backlog);
            channelOptions.put(ChannelOption.TCP_NODELAY,TCP_NODELAY);
            channelOptions.put(ChannelOption.SO_REUSEADDR,reuseaddr);
            bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.childHandler(channelHandler);
            for (Map.Entry<ChannelOption, Object> entry : channelOptions.entrySet()) {
                bootstrap.option(entry.getKey(), entry.getValue());
            }
            serverChannelFuture = bootstrap.bind(new InetSocketAddress(port)).sync();
            logger.info("成功bind端口:" + port);

            serverChannelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            logger.error("启动NETTY TCP异常:", e);
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    /**
     * 开启单独的线程运行netty服务,避免和spring mvc冲突
     */
    public void run() {
        messageExecutor = Executors.newFixedThreadPool(1);
        messageExecutor.execute(() -> init());
    }

    public void destroy() throws Exception {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        serverChannelFuture.channel().closeFuture().sync();
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setChannelOptions(Map<ChannelOption, Object> channelOptions) {
        this.channelOptions = channelOptions;
    }

    public void setChannelHandler(ChannelHandler channelHandler) {
        this.channelHandler = channelHandler;
    }


}
