package com.nms.server.thread.netty;

import java.util.concurrent.Callable;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

import org.apache.log4j.Logger;

import com.nms.server.common.Common;
import com.nms.server.common.Constants;
import com.nms.server.util.socket.SocketUtils;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;
/**
 * netty server
 * 1、实现 ssl 双向认证
 * 2、自定义了消息解析器
 * 	  消息解析器实现：内存缓存最大值 maxMemByte，当消息length 超过 maxMemByte ，将消息内容写入文件，否则通过byte[] 数组的方式保存。
 * 	 消息格式    |   4byte  |  1byte |...........| 
 *          |bodylength|bodyType|    body   |
 * 3、消息的业务处理 在 MessageHandler 中处理
 * @author dell
 *
 */
public class NettyServer implements Callable<Object> {
	private final static Logger logger = Logger.getLogger(NettyServer.class);
	private int port;//监听端口号
	private boolean ssl;//是否启用ssl
	public NettyServer(int port,boolean ssl) {
		this.port = port;
		this.ssl = ssl;
	}
	
	@Override
	public Object call() throws Exception {
		Thread.currentThread().setName("NettyServer");
		logger.debug("Thread start");
		final SSLContext sslContext = SocketUtils.getSSLContext();//ssl认证
		EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		while(!Common.isStop()&& !Thread.currentThread().isInterrupted()){
			try {
				ServerBootstrap b = new ServerBootstrap(); // (2)
				b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
						.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
							@Override
							public void initChannel(SocketChannel ch) throws Exception {
								
								if(ssl){//启用 ssl 通信
									SSLEngine engine = sslContext.createSSLEngine();
									engine.setUseClientMode(false);//服务端模式
									engine.setNeedClientAuth(true);//双向认证
									ch.pipeline().addLast(new SslHandler(engine));
								}
								ch.pipeline().addLast(new IdleStateHandler(0, 0, Constants.NETTY_IDLE_TIME));
								ch.pipeline().addLast(new MessageDecoder());
								ch.pipeline().addLast(new MessageHandler());
							}
						}).option(ChannelOption.SO_BACKLOG, Constants.NETTY_SO_BACKLOG) // (5)
						.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
				ChannelFuture f = b.bind(port).sync(); // (7)
				logger.info("server 启动成功");
				f.channel().closeFuture().sync();
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("",e);
			} finally {
				workerGroup.shutdownGracefully();
				bossGroup.shutdownGracefully();
			}
			logger.info("server 关闭");
		}
		logger.info("thread end");
		return null;
	}

	
	public static void main(String[] args) throws Exception {
		NettyServer server = new NettyServer(9527,true);
		server.call();
	}
	
}
