content: package com.genersoft.iot.vmp.jt1078.codec.netty;
  
  import com.genersoft.iot.vmp.jt1078.codec.decode.Jt808Decoder;
  import com.genersoft.iot.vmp.jt1078.codec.encode.Jt808Encoder;
  import com.genersoft.iot.vmp.jt1078.codec.encode.Jt808EncoderCmd;
  import com.genersoft.iot.vmp.jt1078.proc.factory.CodecFactory;
  import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service;
  import io.netty.bootstrap.ServerBootstrap;
  import io.netty.buffer.ByteBuf;
  import io.netty.buffer.Unpooled;
  import io.netty.channel.ChannelFuture;
  import io.netty.channel.ChannelInitializer;
  import io.netty.channel.EventLoopGroup;
  import io.netty.channel.nio.NioEventLoopGroup;
  import io.netty.channel.socket.nio.NioChannelOption;
  import io.netty.channel.socket.nio.NioServerSocketChannel;
  import io.netty.channel.socket.nio.NioSocketChannel;
  import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  import io.netty.handler.timeout.IdleStateHandler;
  import io.netty.util.concurrent.Future;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.boot.CommandLineRunner;
  import org.springframework.context.ApplicationContextInitializer;
  import org.springframework.context.ApplicationEventPublisher;
  import org.springframework.stereotype.Component;
  import lombok.extern.slf4j.Slf4j;
  
  import java.util.concurrent.TimeUnit;
  
  /**
   * @author QingtaiJiang
   * @date 2023/4/27 18:01
   * @email qingtaij@163.com
   */
  
  @Slf4j
  public class TcpServer {
  
      private final Integer port;
      private boolean isRunning = false;
      private EventLoopGroup bossGroup = null;
      private EventLoopGroup workerGroup = null;
      private ApplicationEventPublisher applicationEventPublisher = null;
      private Ijt1078Service service = null;
  
      private final ByteBuf DECODER_JT808 = Unpooled.wrappedBuffer(new byte[]{0x7e});
  
      public TcpServer(Integer port, ApplicationEventPublisher applicationEventPublisher, Ijt1078Service service) {
          this.port = port;
          this.applicationEventPublisher = applicationEventPublisher;
          this.service = service;
      }
  
      private void startTcpServer() {
          try {
              CodecFactory.init();
              this.bossGroup = new NioEventLoopGroup();
              this.workerGroup = new NioEventLoopGroup();
              ServerBootstrap bootstrap = new ServerBootstrap();
              bootstrap.channel(NioServerSocketChannel.class);
              bootstrap.group(bossGroup, workerGroup);
  
              bootstrap.option(NioChannelOption.SO_BACKLOG, 1024)
                      .option(NioChannelOption.SO_REUSEADDR, true)
                      .childOption(NioChannelOption.TCP_NODELAY, true)
                      .childHandler(new ChannelInitializer<NioSocketChannel>() {
                          @Override
                          public void initChannel(NioSocketChannel channel) {
                              channel.pipeline()
                                      .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.MINUTES))
                                      .addLast(new DelimiterBasedFrameDecoder(1024 * 2, DECODER_JT808))
                                      .addLast(new Jt808Decoder(applicationEventPublisher, service))
                                      .addLast(new Jt808Encoder())
                                      .addLast(new Jt808EncoderCmd())
                                      .addLast(new Jt808Handler(applicationEventPublisher));
                          }
                      });
              ChannelFuture channelFuture = bootstrap.bind(port).sync();
              // 监听设备TCP端口是否启动成功
              channelFuture.addListener(future -> {
                  if (!future.isSuccess()) {
                      log.error("Binding port:{} fail!  cause: {}", port, future.cause().getCause(), future.cause());
                  }
              });
              log.info("服务:JT808 Server 启动成功, port:{}", port);
              channelFuture.channel().closeFuture().sync();
          } catch (Exception e) {
              log.warn("服务:JT808 Server 启动异常, port:{},{}", port, e.getMessage(), e);
          } finally {
              stop();
          }
      }
  
      /**
       * 开启一个新的线程,拉起来Netty
       */
      public synchronized void start() {
          if (this.isRunning) {
              log.warn("服务:JT808 Server 已经启动, port:{}", port);
              return;
          }
          this.isRunning = true;
          new Thread(this::startTcpServer).start();
      }
  
      public synchronized void stop() {
          if (!this.isRunning) {
              log.warn("服务:JT808 Server 已经停止, port:{}", port);
          }
          this.isRunning = false;
          Future<?> future = this.bossGroup.shutdownGracefully();
          if (!future.isSuccess()) {
              log.warn("bossGroup 无法正常停止", future.cause());
          }
          future = this.workerGroup.shutdownGracefully();
          if (!future.isSuccess()) {
              log.warn("workerGroup 无法正常停止", future.cause());
          }
          log.warn("服务:JT808 Server 已经停止, port:{}", port);
      }
  }
  