org.fisco.bcos.channel.handler.ChannelConnections Maven / Gradle / Ivy
package org.fisco.bcos.channel.handler;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.timeout.IdleStateHandler;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException;
import org.fisco.bcos.channel.dto.FiscoMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
public class ChannelConnections {
private static Logger logger = LoggerFactory.getLogger(ChannelConnections.class);
private Callback callback;
private List connectionsStr;
private String caCertPath = "classpath:ca.crt";
private String nodeCaPath = "classpath:node.crt";
private String nodeKeyPath = "classpath:node.key";
private List connections = new ArrayList();
private Boolean running = false;
private ThreadPoolTaskExecutor threadPool;
private long idleTimeout = (long) 10000;
private long heartBeatDelay = (long) 2000;
public Map networkConnections = new HashMap();
private int groupId;
private Bootstrap bootstrap = new Bootstrap();
ServerBootstrap serverBootstrap = new ServerBootstrap();
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
public String getNodeCaPath() {
return nodeCaPath;
}
public void setNodeCaPath(String nodeCaPath) {
this.nodeCaPath = nodeCaPath;
}
public String getNodeKeyPath() {
return nodeKeyPath;
}
public void setNodeKeyPath(String nodeKeyPath) {
this.nodeKeyPath = nodeKeyPath;
}
public interface Callback {
void onConnect(ChannelHandlerContext ctx);
void onDisconnect(ChannelHandlerContext ctx);
void onMessage(ChannelHandlerContext ctx, ByteBuf message);
}
public Callback getCallback() {
return callback;
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public List getConnectionsStr() {
return connectionsStr;
}
public void setConnectionsStr(List connectionsStr) {
this.connectionsStr = connectionsStr;
}
public List getConnections() {
return connections;
}
public void setConnections(List connections) {
this.connections = connections;
}
public ThreadPoolTaskExecutor getThreadPool() {
return threadPool;
}
public void setThreadPool(ThreadPoolTaskExecutor threadPool) {
this.threadPool = threadPool;
}
public long getIdleTimeout() {
return idleTimeout;
}
public void setIdleTimeout(long idleTimeout) {
this.idleTimeout = idleTimeout;
}
public long getHeartBeatDelay() {
return heartBeatDelay;
}
public void setHeartBeatDelay(long heartBeatDelay) {
this.heartBeatDelay = heartBeatDelay;
}
public String getCaCertPath() {
return caCertPath;
}
public void setCaCertPath(String caCertPath) {
this.caCertPath = caCertPath;
}
public ChannelHandlerContext randomNetworkConnection() throws Exception {
List activeConnections = new ArrayList();
for (String key : networkConnections.keySet()) {
if (networkConnections.get(key) != null && networkConnections.get(key).channel().isActive()) {
activeConnections.add(networkConnections.get(key));
}
}
if (activeConnections.isEmpty()) {
logger.error("activeConnections isEmpty");
throw new Exception("activeConnections isEmpty");
}
Random random = new SecureRandom();
Integer index = random.nextInt(activeConnections.size());
logger.debug("selected:{}", index);
return activeConnections.get(index);
}
public ConnectionInfo getConnectionInfo(String host, Integer port) {
for (ConnectionInfo info : connections) {
if (info.getHost().equals(host) && info.getPort().equals(port)) {
return info;
}
}
return null;
}
public Map getNetworkConnections() {
return networkConnections;
}
public ChannelHandlerContext getNetworkConnectionByHost(String host, Integer port) {
String endpoint = host + ":" + port;
return networkConnections.get(endpoint);
}
public void setNetworkConnectionByHost(String host, Integer port, ChannelHandlerContext ctx) {
String endpoint = host + ":" + port;
networkConnections.put(endpoint, ctx);
}
public void removeNetworkConnectionByHost(String host, Integer port) {
String endpoint = host + ":" + port;
networkConnections.remove(endpoint);
}
public void startListen(Integer port) throws SSLException {
if (running) {
logger.debug("running");
return;
}
logger.debug("init connections listen");
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
final ChannelConnections selfService = this;
final ThreadPoolTaskExecutor selfThreadPool = threadPool;
SslContext sslCtx = initSslContextForListening();
logger.debug("listening sslcontext init success");
try {
serverBootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(
new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
/*
* 每次连接使用新的handler
* 连接信息从socketChannel中获取
*/
ChannelHandler handler = new ChannelHandler();
handler.setConnections(selfService);
handler.setIsServer(true);
handler.setThreadPool(selfThreadPool);
ch.pipeline()
.addLast(
sslCtx.newHandler(ch.alloc()),
new LengthFieldBasedFrameDecoder(1024 * 1024 * 4, 0, 4, -4, 0),
new IdleStateHandler(
idleTimeout, idleTimeout, idleTimeout, TimeUnit.MILLISECONDS),
handler);
}
});
ChannelFuture future = serverBootstrap.bind(port);
future.get();
running = true;
} catch (Exception e) {
logger.error("error ", e);
}
}
public void init() {
logger.debug("init connections");
// 初始化connections
for (String conn : connectionsStr) {
ConnectionInfo connection = new ConnectionInfo();
String[] split2 = conn.split(":");
connection.setHost(split2[0]);
connection.setPort(Integer.parseInt(split2[1]));
networkConnections.put(conn, null);
logger.debug("add direct node :[" + "]:[" + split2[1] + "]");
connection.setConfig(true);
connections.add(connection);
}
}
public void startConnect() throws SSLException {
if (running) {
logger.debug("running");
return;
}
logger.debug("init connections connect");
// 初始化netty
EventLoopGroup workerGroup = new NioEventLoopGroup();
bootstrap.group(workerGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
final ChannelConnections selfService = this;
final ThreadPoolTaskExecutor selfThreadPool = threadPool;
SslContext sslCtx = initSslContextForConnect();
logger.debug(" connect sslcontext init success");
bootstrap.handler(
new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
/*
* 每次连接使用新的handler 连接信息从socketChannel中获取
*/
ChannelHandler handler = new ChannelHandler();
handler.setConnections(selfService);
handler.setIsServer(false);
handler.setThreadPool(selfThreadPool);
ch.pipeline()
.addLast(
sslCtx.newHandler(ch.alloc()),
new LengthFieldBasedFrameDecoder(1024 * 1024 * 4, 0, 4, -4, 0),
new IdleStateHandler(
idleTimeout, idleTimeout, idleTimeout, TimeUnit.MILLISECONDS),
handler);
}
});
running = true;
Thread loop =
new Thread() {
public void run() {
try {
while (true) {
if (!running) {
return;
}
// 尝试重连
reconnect();
Thread.sleep(heartBeatDelay);
}
} catch (InterruptedException e) {
logger.error("error", e);
Thread.currentThread().interrupt();
}
}
};
loop.start();
}
private SslContext initSslContextForConnect() throws SSLException {
SslContext sslCtx;
try {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource caResource = resolver.getResource(getCaCertPath());
InputStream caInputStream = caResource.getInputStream();
Resource keystorecaResource = resolver.getResource(getNodeCaPath());
Resource keystorekeyResource = resolver.getResource(getNodeKeyPath());
sslCtx =
SslContextBuilder.forClient()
.trustManager(caInputStream)
.keyManager(keystorecaResource.getInputStream(), keystorekeyResource.getInputStream())
.sslProvider(SslProvider.JDK)
.build();
} catch (Exception e) {
logger.debug("SSLCONTEXT ***********" + e.getMessage());
throw new SSLException("Failed to initialize the client-side SSLContext: " + e.getMessage());
}
return sslCtx;
}
private SslContext initSslContextForListening() throws SSLException {
SslContext sslCtx;
try {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource caResource = resolver.getResource(getCaCertPath());
InputStream caInputStream = caResource.getInputStream();
Resource keystorecaResource = resolver.getResource(getNodeCaPath());
Resource keystorekeyResource = resolver.getResource(getNodeKeyPath());
sslCtx =
SslContextBuilder.forServer(
keystorecaResource.getInputStream(), keystorekeyResource.getInputStream())
.trustManager(caInputStream)
.build();
} catch (Exception e) {
logger.debug("SSLCONTEXT ***********" + e.getMessage());
throw new SSLException(
"Failed to initialize the client-side SSLContext, please checkout ca.crt File!", e);
}
return sslCtx;
}
public void reconnect() {
for (Entry ctx : networkConnections.entrySet()) {
if (ctx.getValue() == null || !ctx.getValue().channel().isActive()) {
String[] split = ctx.getKey().split(":");
String host = split[0];
Integer port = Integer.parseInt(split[1]);
logger.debug("try connect to: {}:{}", host, port);
bootstrap.connect(host, port);
logger.debug("connect to: {}:{} success", host, port);
} else {
logger.trace("send heart beat to {}", ctx.getKey());
// 连接还在,发送心跳
FiscoMessage fiscoMessage = new FiscoMessage();
fiscoMessage.setSeq(UUID.randomUUID().toString().replaceAll("-", ""));
fiscoMessage.setResult(0);
fiscoMessage.setType((short) 0x13);
fiscoMessage.setData("0".getBytes());
ByteBuf out = ctx.getValue().alloc().buffer();
fiscoMessage.writeHeader(out);
fiscoMessage.writeExtra(out);
ctx.getValue().writeAndFlush(out);
}
}
}
public void onReceiveMessage(ChannelHandlerContext ctx, ByteBuf message) {
callback.onMessage(ctx, message);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy