All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fisco.bcos.channel.proxy.Server Maven / Gradle / Ivy

There is a newer version: 2.6.6
Show newest version
package org.fisco.bcos.channel.proxy;

import com.fasterxml.jackson.databind.ObjectMapper;
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.Timer;
import org.fisco.bcos.channel.handler.ChannelConnections;
import org.fisco.bcos.channel.handler.ConnectionInfo;
import org.fisco.bcos.channel.handler.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.net.ssl.SSLException;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

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 if(msg.getType() == 0x1000) {
					logger.debug("transaction message call back.");
				}
				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() throws SSLException {
		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 SecureRandom();
				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 - 2024 Weber Informatics LLC | Privacy Policy