/*
* Copyright (c) 2016.
* chinaume@163.com
*/
package com.goav.netty.Handler;
import com.goav.netty.Impl.ResponseListener;
import com.google.gson.JsonElement;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
/**
* 长链接<p>
* <p>
* 后期替换推送 in future.
* </p>
*
* @time: 16/10/8 12:41.<br/>
* @author: Created by moo<br/>
*/
class Client extends ClientImpl {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Client.class);
private SocketChannel socketChannel;
private ScheduledExecutorService service;
private ResponseChannelHandler handler;
private BlockingDeque<Object> messageSupers;
private boolean onDestrOY = false;
private String host;
private int port;
@Override
public void onConnectChange(boolean isConnect) {
if (!getConnectState() && isConnect) {
reset2Connect();
}
}
private static class ClientHelper {
final static Client CLIENT = new Client();
}
private Client() {
service = Executors.newSingleThreadScheduledExecutor();
handler = new ResponseChannelHandler();
messageSupers = new LinkedBlockingDeque<>();
request();
}
@Override
public void Initialization() {
reset2Connect();
}
public void InitializationWithWorkThread() {
if (socketChannel != null && socketChannel.isOpen() && socketChannel.isActive()) {
logger.info("socket 已经建立了链接");
return;
}
onDestrOY = false;
// Object host = Constants.Address.valueOf(Constants.SOCKET.HOST);
// Object port = Constants.Address.valueOf(Constants.SOCKET.PORT);
if (host == null || port == 0) {
return;
}
Bootstrap bootstrap = new Bootstrap();
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
bootstrap
.channel(NioSocketChannel.class)
.group(eventLoopGroup)
.option(ChannelOption.SO_KEEPALIVE, true)
.remoteAddress(host, port)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(60, 60, 90));
ch.pipeline().addLast(new EncodeHandler());
ch.pipeline().addLast(new DecodeHandler());
ch.pipeline().addLast(new CloseChannelHandler(Client.this));
ch.pipeline().addLast(handler);
}
});
ChannelFuture future = bootstrap.connect().sync();
if (future.isSuccess()) {
socketChannel = (SocketChannel) future.channel();
logger.info("socketChannel连接成功");
} else {
throw new InterruptedException("connection fail.");
}
} catch (Exception e) {
logger.info("socketChannel连接失败");
logger.info(e);
// eventLoopGroup.shutdownGracefully();//it's can't restart when server close
onDestroy();
reset2Connect();
//重置,重启
}
}
private void request() {
new Thread("Socket_Push_Message") {
@Override
public void run() {
while (!onDestrOY) {
Object message = null;
try {
message = messageSupers.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (message != null && getConnectState()) {
socketChannel.writeAndFlush(message);
}
}
}
}.start();
}
@Override
public void request(Object message) {
try {
messageSupers.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public boolean getConnectState() {
return socketChannel != null && socketChannel.isActive();
}
@Override
protected void restart(boolean restart) {
reset();
if (!getConnectState() && restart && !onDestrOY) {
reset2Connect();
}
}
@Override
protected void close() {
socketChannel = null;
}
@Override
public void onDestroy() {
onDestrOY = true;
messageSupers.clear();
reset();
}
@Override
public ClientImpl addResponseListener(ResponseListener<? super JsonElement> response) {
handler.addListener(response);
return this;
}
@Override
public ClientImpl addResponseListener(ResponseChannelHandler response) {
handler = response;
return this;
}
@Override
public ClientImpl bind(String host, int port) {
this.host = host;
this.port = port;
return this;
}
private void reset() {
if (socketChannel != null) {
socketChannel.close();
}
}
private void reset2Connect() {
logger.info("socket 连接2s后建立");
service.schedule(new Runnable() {
@Override
public void run() {
InitializationWithWorkThread();
}
}, 2, TimeUnit.SECONDS);
}
public static ClientImpl newInstances() {
return ClientHelper.CLIENT;
}
}