package com.willalp.control.netty;

import cn.hutool.core.thread.NamedThreadFactory;
import com.willalp.control.netty.handler.DeviceChannelHandler;
import com.willalp.control.netty.model.ChannelMsgModel;
import com.willalp.control.netty.model.ControlDataModel;
import com.willalp.control.netty.model.DeviceChannelMap;
import com.willalp.device.mapper.DeviceMapper;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author hs
 */
@Data
@Component
@ConfigurationProperties(prefix = "netty")
public class NettyServer {

    protected final static Logger logger = LoggerFactory.getLogger(NettyServer.class);

    /**
     * 处理器核心数
     */
    @Value("${netty.server-config.serverCoreNum}")
    private static int serverCoreNum;

    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private ControlDataModel dataModel;

    /**
     * 控制线程数，最优选择是处理器线程数*3
     */
    private static final int THREAD_COUNT = serverCoreNum * 3;

    public static final ExecutorService THREAD_POOL = new ThreadPoolExecutor(THREAD_COUNT,
            300,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<>(),
            new NamedThreadFactory("netty", false));

    /**
     * 设备控制中心端口
     */
    @Value("${netty.server-port.deviceControlCorePort}")
    private int deviceControlCorePort;


    public void start() {
        //设备控制中心 ：8802
        THREAD_POOL.submit(() -> new TcpServer(
                deviceControlCorePort/*端口*/,
                new DeviceChannelHandler(/*注入service*/deviceMapper,dataModel))/*业务处理*/
                .init(channel -> DeviceChannelMap.add(Tool.subRemoteAddr(channel.remoteAddress().toString()),
                        new ChannelMsgModel().setChannel(channel).setLastChange(new Date()))));
    }
}
