org.bcos.channel.proxy.Server Maven / Gradle / Ivy
package org.bcos.channel.proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bcos.channel.handler.ChannelConnections;
import org.bcos.channel.handler.ConnectionInfo;
import org.bcos.channel.handler.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
public class Server {
private static Logger logger = LoggerFactory.getLogger(Server.class);
class ConnectionCallback implements ChannelConnections.Callback {
public Server getServer() {
return server;
}
public void setServer(Server server) {
this.server = server;
}
public Boolean getFromRemote() {
return fromRemote;
}
public void setFromRemote(Boolean fromRemote) {
this.fromRemote = fromRemote;
}
@Override
public void onMessage(ChannelHandlerContext ctx, ByteBuf message) {
try {
Message msg = new Message();
msg.readHeader(message);
msg.readExtra(message);
logger.debug("receive Message type: {}", msg.getType());
if(msg.getType() == 0x20 || msg.getType() == 0x21) {
logger.debug("channel ");
}
else if(msg.getType() == 0x30 || msg.getType() == 0x31) {
logger.debug("channel2");
}
else if(msg.getType() == 0x32) {
logger.debug("topic");
onTopic(ctx, msg);
return;
}
else if(msg.getType() == 0x12) {
logger.debug("ethereum");
}
else if(msg.getType() == 0x13) {
onHeartBeat(ctx, msg);
return;
}
else {
logger.error("unknown message:{}", msg.getType());
}
if(fromRemote) {
logger.debug("remote message");
server.onRemoteMessage(ctx, msg);
}
else {
logger.debug("local message");
server.onLocalMessage(ctx, msg);
}
}
finally {
message.release();
}
}
@Override
public void onConnect(ChannelHandlerContext ctx) {
//成功连接到新节点,发送topic
if(fromRemote) {
try {
logger.debug("endpoint connection established,send topic");
broadcastTopic(ctx);
} catch (Exception e) {
logger.error("error ", e);
}
}
}
@Override
public void onDisconnect(ChannelHandlerContext ctx) {
//有sdk断开,需更新topic
if(!fromRemote) {
//需要清除该连接的信息
logger.debug("SDK disconnect,update and broadcast topic");
broadcastTopic();
}
}
private Server server;
private Boolean fromRemote = false;
}
public ChannelConnections getLocalConnections() {
return localConnections;
}
public void setLocalConnections(ChannelConnections localConnections) {
this.localConnections = localConnections;
}
public ChannelConnections getRemoteConnections() {
return remoteConnections;
}
public void setRemoteConnections(ChannelConnections connections) {
this.remoteConnections = connections;
}
public Map getSeq2Connections() {
return seq2Connections;
}
public void setSeq2Connections(Map seq2Connections) {
this.seq2Connections = seq2Connections;
}
public Integer getBindPort() {
return bindPort;
}
public void setBindPort(Integer bindPort) {
this.bindPort = bindPort;
}
public Timer getTimeoutHandler() {
return timeoutHandler;
}
public void setTimeoutHandler(Timer timeoutHandler) {
this.timeoutHandler = timeoutHandler;
}
public void run() {
logger.debug("init ProxyServer");
try {
ConnectionCallback localConnectionCallback = new ConnectionCallback();
localConnectionCallback.setServer(this);
localConnectionCallback.setFromRemote(false);
ConnectionCallback remoteConnectionCallback = new ConnectionCallback();
remoteConnectionCallback.setServer(this);
remoteConnectionCallback.setFromRemote(true);
localConnections.setCallback(localConnectionCallback);
localConnections.startListen(bindPort);
remoteConnections.setCallback(remoteConnectionCallback);
remoteConnections.init();
remoteConnections.setThreadPool(threadPool);
remoteConnections.startConnect();
} catch (Exception e) {
logger.error("error ", e);
throw e;
}
}
public void broadcastTopic() {
broadcastTopic(null);
}
public void broadcastTopic(ChannelHandlerContext ctx) {
try {
Message message = new Message();
message.setResult(0);
message.setType((short)0x32); //topic设置topic消息0x32
message.setSeq(UUID.randomUUID().toString().replaceAll("-", ""));
//综合所有的topics
Set allTopics = new HashSet();
for(ConnectionInfo connectionInfo: localConnections.getConnections()) {
//有效的连接,才增加到全局topic
ChannelHandlerContext localCtx = localConnections.getNetworkConnectionByHost(connectionInfo.getHost(), connectionInfo.getPort());
if(localCtx != null && localCtx.channel().isActive()) {
logger.debug("node:{}:{} follow topics: {}", connectionInfo.getHost(), connectionInfo.getPort(), connectionInfo.getTopics());
allTopics.addAll(connectionInfo.getTopics());
}
}
message.setData(objectMapper.writeValueAsBytes(allTopics.toArray()));
logger.debug("all topics: {}", new String(message.getData()));
if(ctx == null) {
//广播到所有远端节点
for(String key: remoteConnections.getNetworkConnections().keySet()) {
ChannelHandlerContext remoteCtx = remoteConnections.getNetworkConnections().get(key);
if(remoteCtx != null && remoteCtx.channel().isActive()) {
ByteBuf out = remoteCtx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
if(remoteCtx != null && remoteCtx.channel().isActive()) {
logger.debug("send topic {}:{}", ((SocketChannel) remoteCtx.channel()).remoteAddress().getAddress().getHostAddress(),
((SocketChannel) remoteCtx.channel()).remoteAddress().getPort());
remoteCtx.writeAndFlush(out);
}
}
}
}
else {
//发送到指定远端节点
logger.debug("topic send to {}:{}", ((SocketChannel) ctx.channel()).remoteAddress().getAddress().getHostAddress(),
((SocketChannel) ctx.channel()).remoteAddress().getPort());
ByteBuf out = ctx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
ctx.writeAndFlush(out);
}
}
catch(Exception e) {
logger.error("error ", e);
}
}
public void onLocalMessage(ChannelHandlerContext ctx, Message message) {
try {
logger.debug("sdk request: " + message.getSeq());
ChannelHandlerContext remoteCtx = null;
ConnectionPair pair = seq2Connections.get(message.getSeq());
if (pair != null) {
// 已有这个seq,发往远端的响应
logger.debug("seq existed");
// 发送到远端的响应
remoteCtx = pair.remoteConnection;
if(message.getType() != 0x31) {
pair.localConnection = ctx;
}
ByteBuf out = remoteCtx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
logger.debug("msg send to:{}:{}", ((SocketChannel) remoteCtx.channel()).remoteAddress().getAddress().getHostAddress(),
((SocketChannel) remoteCtx.channel()).remoteAddress().getPort());
remoteCtx.writeAndFlush(out);
} else {
pair = new ConnectionPair();
pair.localConnection = ctx;
pair.setServer(this);
pair.setMessage(message);
// 没有这个seq,可能是新发请求或者新收到的push
// 本地发往远程的消息,如果是链上链下,需要按给定的nodeID发
if (message.getType() == 0x20 || message.getType() == 0x21) {
// 获取nodeID
logger.debug("channel message v1");
if (message.getData().length < 256) {
logger.error("wrong channel message, length less than 256:{}", message.getData().length);
}
// 获取nodeID对应的连接,检查可用性
String nodeID = new String(message.getData(), 128, 128);
logger.debug("forward:{}", nodeID, message.getData());
for (ConnectionInfo conn : remoteConnections.getConnections()) {
if (conn.getNodeID().equals(nodeID)) {
remoteCtx = remoteConnections.getNetworkConnectionByHost(conn.getHost(), conn.getPort());
pair.remoteConnection = remoteCtx;
break;
}
}
if (remoteCtx == null || !remoteCtx.channel().isActive()) {
// 找不到连接,错误
logger.error("connect exception,error 99");
if(message.getType() == 0x20 || message.getType() == 0x21) {
message.setType((short) 0x21);
}
else {
message.setType((short) 0x31);
}
message.setResult(99);
ByteBuf out = ctx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
ctx.writeAndFlush(out);
return;
}
ByteBuf out = remoteCtx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
logger.debug("send to:{}:{}", ((SocketChannel) remoteCtx.channel()).remoteAddress().getAddress().getHostAddress(),
((SocketChannel) remoteCtx.channel()).remoteAddress().getPort());
remoteCtx.writeAndFlush(out);
pair.init();
} else {
logger.debug("other type message,ConnectionPair");
pair.setRemoteChannelConnections(remoteConnections);
List remoteConnectionInfos = new ArrayList();
remoteConnectionInfos.addAll(remoteConnections.getConnections());
pair.setRemoteConnectionInfos(remoteConnectionInfos);
seq2Connections.put(message.getSeq(), pair);
pair.init();
pair.retrySendRemoteMessage();
}
}
} catch (Exception e) {
logger.error("error ", e);
}
}
public void onRemoteMessage(ChannelHandlerContext ctx, Message message) {
try {
logger.debug("processing : " + message.getSeq());
ChannelHandlerContext localCtx = null;
ConnectionPair pair = seq2Connections.get(message.getSeq());
if(message.getType() == 0x30) {
//链上链下二期,需要找到关注该topic的连接
Short length = (short) message.getData()[0];
String topic = new String(message.getData(), 1, length - 1);
Set topicCtxs = new HashSet();
for (ConnectionInfo connectionInfo : localConnections.getConnections()) {
if(connectionInfo.getTopics().contains(topic)) {
ChannelHandlerContext topicCtx = localConnections.getNetworkConnectionByHost(connectionInfo.getHost(), connectionInfo.getPort());
if(topicCtx != null && topicCtx.channel().isActive()) {
topicCtxs.add(topicCtx);
}
}
}
logger.debug("send topic:{} sum{} follow topic", topic, topicCtxs.size());
if(topicCtxs.isEmpty()) {
// 找不到连接,错误
logger.error("connection not found,error 99");
message.setType((short) 0x31);
message.setResult(99);
ByteBuf out = ctx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
ctx.writeAndFlush(out);
return;
}
//随机下发
Random random = new Random();
Integer index = random.nextInt(topicCtxs.size());
ChannelHandlerContext target = (ChannelHandlerContext) topicCtxs.toArray()[index];
logger.debug("send to {}:{}", ((SocketChannel) target.channel()).remoteAddress().getAddress().getHostAddress(),
((SocketChannel) target.channel()).remoteAddress().getPort());
localCtx = target;
if(pair == null) {
pair = new ConnectionPair();
pair.localConnection = localCtx;
pair.remoteConnection = ctx;
pair.setServer(this);
pair.setMessage(message);
seq2Connections.put(message.getSeq(), pair);
pair.init();
}
else {
pair.remoteConnection = ctx;
}
}
else {
if (pair != null) {
// 已有这个seq,可能是发送响应或者收到回包消息
logger.debug("seq existed");
// 收到来自远端的回包
localCtx = pair.localConnection;
if(message.getResult() != 0 && message.getType() == 0x31) {
//链上链下二期错误时,执行retry
logger.error("endpoint error:{},retry", message.getResult());
pair.retrySendRemoteMessage();
return;
}
pair.remoteConnection = ctx;
} else {
// 没有这个seq,可能是新发请求或者新收到的push
//其他消息(链上链下一期),随机发
localCtx = localConnections.randomNetworkConnection();
}
}
if (localCtx == null || !localCtx.channel().isActive()) {
// 找不到连接,错误
logger.error("connect unavailable,error 99");
if(message.getType() == 0x20 || message.getType() == 0x21) {
message.setType((short) 0x21);
}
else {
message.setType((short) 0x31);
}
message.setResult(99);
ByteBuf out = ctx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
ctx.writeAndFlush(out);
return;
}
ByteBuf out = localCtx.alloc().buffer();
message.writeHeader(out);
message.writeExtra(out);
logger.debug("send to:{}:{}", ((SocketChannel) localCtx.channel()).remoteAddress().getAddress().getHostAddress(),
((SocketChannel) localCtx.channel()).remoteAddress().getPort());
localCtx.writeAndFlush(out);
} catch (Exception e) {
logger.error("error ", e);
}
}
public void onHeartBeat(ChannelHandlerContext ctx, Message message) {
String content = "1";
try {
content = new String(message.getData(), "utf-8");
} catch (UnsupportedEncodingException e) {
logger.error("unexpected heartbeat ");
} catch (Exception e) {
logger.error("heartbeat error");
}
if(content.equals("0")) {
Message response = new Message();
response.setSeq(message.getSeq());
response.setResult(0);
response.setType((short) 0x13);
response.setData("1".getBytes());
ByteBuf out = ctx.alloc().buffer();
response.writeHeader(out);
response.writeExtra(out);
ctx.writeAndFlush(out);
}
else if(content.equals("1")) {
}
}
public void onTopic(ChannelHandlerContext ctx, Message message) {
logger.debug("SDK topics message: {} {}", message.getSeq(), new String(message.getData()));
String host = ((SocketChannel)ctx.channel()).remoteAddress().getAddress().getHostAddress();
Integer port = ((SocketChannel)ctx.channel()).remoteAddress().getPort();//
ConnectionInfo info = localConnections.getConnectionInfo(host, port);
if(info != null) {
try {
List topics = objectMapper.readValue(message.getData(), List.class);
info.setTopics(topics);
broadcastTopic();
} catch (Exception e) {
logger.error("parse topic error", e);
}
}
}
public ThreadPoolTaskExecutor getThreadPool() {
return threadPool;
}
public void setThreadPool(ThreadPoolTaskExecutor threadPool) {
this.threadPool = threadPool;
}
//private String orgID;
private ChannelConnections localConnections = new ChannelConnections();
private ChannelConnections remoteConnections;
private Map seq2Connections = new ConcurrentHashMap();
private Integer bindPort = 8830;
private ObjectMapper objectMapper = new ObjectMapper();
private Timer timeoutHandler = new HashedWheelTimer();
private ThreadPoolTaskExecutor threadPool;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy